package com.hyt.it.ogt.kq.service.bm.service.impl;

import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson15.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.hyt.check.CheckUtil;
import com.hyt.check.ruler.summary.IdCardRuler;
import com.hyt.check.ruler.summary.StrRuler;
import com.hyt.common.apiInfor.ApiResponse;
import com.hyt.core.base.BaseEntity;
import com.hyt.core.base.BaseServiceImpl;
import com.hyt.core.constant.CommonConstant;
import com.hyt.core.enums.DelFlagEnum;
import com.hyt.core.exception.CheckException;
import com.hyt.core.util.FastJsonUtil;
import com.hyt.core.util.RemoteUtil;
import com.hyt.core.util.UUIDUtils;
import com.hyt.enumeration.IdCardTypeEnum;
import com.hyt.exception.exception.BusinessLogicException;
import com.hyt.it.ogt.cj.enums.ComponentNameEnum;
import com.hyt.it.ogt.cj.enums.ComponentTypeEnum;
import com.hyt.it.ogt.cj.model.entity.ProjectCollectInfo;
import com.hyt.it.ogt.cj.model.entity.ProjectCollectInfoOption;
import com.hyt.it.ogt.cj.model.entity.ProjectImageStandard;
import com.hyt.it.ogt.cj.model.vo.ProjectCollectInfoVo;
import com.hyt.it.ogt.cj.service.IProjectCollectInfoOptionService;
import com.hyt.it.ogt.cj.service.IProjectCollectInfoService;
import com.hyt.it.ogt.cj.service.IProjectImageStandardService;
import com.hyt.it.ogt.cj.utils.ExcelExportUtil;
import com.hyt.it.ogt.kq.common.bm.config.RedisKeyConstant;
import com.hyt.it.ogt.kq.common.bm.enums.BmAuditInfoSubmitAgainStatus;
import com.hyt.it.ogt.kq.common.bm.enums.BmAuditStatusEnum;
import com.hyt.it.ogt.kq.common.bm.enums.BmCustomerIntefaceState;
import com.hyt.it.ogt.kq.common.bm.enums.BmPayStatusEnum;
import com.hyt.it.ogt.kq.common.bm.enums.BmProjectCcollectInfoRequiredEnum;
import com.hyt.it.ogt.kq.common.bm.enums.BmProjectNeedAuditEnum;
import com.hyt.it.ogt.kq.common.bm.enums.BmProjectNeedPayEnum;
import com.hyt.it.ogt.kq.common.bm.enums.BmProjectVerifyEnum;
import com.hyt.it.ogt.kq.common.bm.enums.BmStatusEnum;
import com.hyt.it.ogt.kq.common.bm.enums.CertificateTypeEnum;
import com.hyt.it.ogt.kq.common.bm.enums.ProjectDownLoadFileTypeEnum;
import com.hyt.it.ogt.kq.common.bm.enums.ProjectDownLoadStatusEnum;
import com.hyt.it.ogt.kq.common.bm.enums.ProjectOpenEnum;
import com.hyt.it.ogt.kq.common.bm.utils.BmFileUtils;
import com.hyt.it.ogt.kq.common.bm.utils.Constant;
import com.hyt.it.ogt.kq.common.bm.utils.DateUtil;
import com.hyt.it.ogt.kq.common.bm.utils.IDCardUtil;
import com.hyt.it.ogt.kq.common.config.ConfigManager;
import com.hyt.it.ogt.kq.common.config.exception.InvalidRequestException;
import com.hyt.it.ogt.kq.common.enums.UserTypeEnum;
import com.hyt.it.ogt.kq.common.gov.utils.Constants;
import com.hyt.it.ogt.kq.common.utils.CompareUtil;
import com.hyt.it.ogt.kq.common.utils.KqStringUtils;
import com.hyt.it.ogt.kq.service.bm.den.EasyexcelUtil;
import com.hyt.it.ogt.kq.service.bm.den.ExcelExport;
import com.hyt.it.ogt.kq.service.bm.den.UploadFileToHuaweiUtil;
import com.hyt.it.ogt.kq.service.bm.feign.kw.KwClient;
import com.hyt.it.ogt.kq.service.bm.mapper.NonOpenMapper;
import com.hyt.it.ogt.kq.service.bm.mapper.ProjectMapper;
import com.hyt.it.ogt.kq.service.bm.mapper.ProjectSubjectMapper;
import com.hyt.it.ogt.kq.service.bm.mapper.StudentInfoMapper;
import com.hyt.it.ogt.kq.service.bm.mapper.StudentProjectMapper;
import com.hyt.it.ogt.kq.service.bm.mapper.StudentSubjectMapper;
import com.hyt.it.ogt.kq.service.bm.mapper.StudentVerifyMapper;
import com.hyt.it.ogt.kq.service.bm.model.dto.BatchImportFileStatisticDTO;
import com.hyt.it.ogt.kq.service.bm.model.dto.BatchImportTemplateDTO;
import com.hyt.it.ogt.kq.service.bm.model.dto.ExcelDto;
import com.hyt.it.ogt.kq.service.bm.model.dto.FjzfSyncStudentDto;
import com.hyt.it.ogt.kq.service.bm.model.dto.ProjectStatusAttrDto;
import com.hyt.it.ogt.kq.service.bm.model.entity.NonOpenInfo;
import com.hyt.it.ogt.kq.service.bm.model.entity.Project;
import com.hyt.it.ogt.kq.service.bm.model.entity.ProjectDataDownLoadRecord;
import com.hyt.it.ogt.kq.service.bm.model.entity.ProjectSubject;
import com.hyt.it.ogt.kq.service.bm.model.entity.ProjectSubjectAreaLimit;
import com.hyt.it.ogt.kq.service.bm.model.entity.StudentDetail;
import com.hyt.it.ogt.kq.service.bm.model.entity.StudentInfo;
import com.hyt.it.ogt.kq.service.bm.model.entity.StudentProject;
import com.hyt.it.ogt.kq.service.bm.model.entity.StudentSubject;
import com.hyt.it.ogt.kq.service.bm.model.entity.StudentVerify;
import com.hyt.it.ogt.kq.service.bm.model.param.BatchImportManualParam;
import com.hyt.it.ogt.kq.service.bm.model.param.GroupRegistrationExamineeInfo;
import com.hyt.it.ogt.kq.service.bm.model.param.ProjectStudentImportRecordParam;
import com.hyt.it.ogt.kq.service.bm.model.vo.BatchSaveImportDataVO;
import com.hyt.it.ogt.kq.service.bm.model.vo.ImportStudentDataVO;
import com.hyt.it.ogt.kq.service.bm.model.vo.ImportStudentVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.ProjectSubjectVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.StudentInfoDeatailVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.StudentInfoListVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.StudentInfoParam;
import com.hyt.it.ogt.kq.service.bm.model.vo.StudentInfoVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.StudentParam;
import com.hyt.it.ogt.kq.service.bm.model.vo.StudentProjectInfoVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.StudentProjectVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.StudentSubjectDetailVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.StudentSubjectExportVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.StudentVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.UserPermissionStatVo;
import com.hyt.it.ogt.kq.service.bm.mq.GroupRegistrationDataProducer;
import com.hyt.it.ogt.kq.service.bm.service.INonOpenService;
import com.hyt.it.ogt.kq.service.bm.service.IProjectDataDownLoadRecordService;
import com.hyt.it.ogt.kq.service.bm.service.IProjectService;
import com.hyt.it.ogt.kq.service.bm.service.IProjectSubjectAreaLimitService;
import com.hyt.it.ogt.kq.service.bm.service.IProjectSubjectService;
import com.hyt.it.ogt.kq.service.bm.service.IStudentInfoService;
import com.hyt.it.ogt.kq.service.bm.service.IStudentProjectService;
import com.hyt.it.ogt.kq.service.bm.service.IStudentSubjectService;
import com.hyt.it.ogt.kq.service.gov.den.TencentCloudCosUtil;
import com.hyt.it.ogt.kq.service.gov.feign.tps.GovTpsClient;
import com.hyt.it.ogt.kq.service.model.entity.Candidate;
import com.hyt.it.ogt.kq.service.model.entity.admission.CandidateInfo;
import com.hyt.it.ogt.kq.service.model.param.PushCandidateParam;
import com.hyt.loginfo.model.ExamineeRegisterVO;
import com.hyt.loginfo.model.User;
import com.hyt.loginfo.model.UserPhoneEditVO;
import com.hyt.loginfo.remote.PermissionLoginClient;
import com.hyt.loginfo.service.IBaseLoginService;
import com.hyt.model.PageParam;
import com.hyt.model.tps.vo.Bucket;
import com.hyt.progress.constants.ProgressConstant;
import com.hyt.progress.service.ProgressManager;
import com.hyt.util.MD5Util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 考生基础信息 服务实现类
 * </p>
 *
 * @author wangt
 * @since 2020-05-15
 */
@Service
@Slf4j
public class StudentInfoServiceImpl extends BaseServiceImpl<StudentInfoMapper, StudentInfo> implements IStudentInfoService {

    private static final Integer TITLE_SIZE = 20;
    @Resource
    private ConfigManager configManager;
    @Resource
    private StudentInfoMapper studentInfoMapper;
    @Resource
    private StudentSubjectMapper studentSubjectMapper;
    @Resource
    private StudentProjectMapper studentProjectMapper;
    @Resource
    private ProjectMapper projectMapper;
    @Resource
    private ProjectSubjectMapper projectSubjectMapper;
    @Resource
    private IProjectCollectInfoService iProjectCollectInfoService;
    @Resource
    IProjectCollectInfoOptionService iProjectCollectInfoOptionService;
    @Resource
    private KwClient kwClient;
    @Resource
    IStudentProjectService iStudentProject;
    @Resource
    IStudentSubjectService iStudentSubjectService;
    @Resource
    private IProjectImageStandardService iProjectImageStandardService;
    @Resource
    private IProjectService iProjectService;
    @Resource
    private ExcelExport excelExport;
    @Resource
    private UploadFileToHuaweiUtil uploadFileToHuaweiUtil;
    @Resource
    private PermissionLoginClient permissionLoginClient;
    @Resource
    private IProjectSubjectService iProjectSubjectService;
    @Resource
    private NonOpenMapper nonOpenMapper;
    @Resource
    private INonOpenService iNonOpenService;
    @Resource
    private IProjectDataDownLoadRecordService iProjectDataDownLoadRecordService;
    @Resource
    private GroupRegistrationDataProducer groupRegistrationDataProducer;
    @Resource
    private StudentVerifyMapper studentVerifyMapper;
    @Resource
    private IBaseLoginService iBaseLoginService;
    @Resource
    private IProjectSubjectAreaLimitService iProjectSubjectAreaLimitService;
    @Resource
    private GovTpsClient tpsClient;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    IStudentProjectService iStudentProjectService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public String saveList(Project project, List<StudentInfo> studentInfos, StudentInfoListVo studentInfoListVo) {
        // 项目ID
        String projectId = project.getId();
        // 考生用户ID
        String regId = studentInfoListVo.getRegId();
        // 是否是集体报名
        Boolean groupRegist = studentInfoListVo.getGroupRegist();
        // 是否创建账号
        Boolean createFlag = studentInfoListVo.getCreateFlag();
        log.info("## studentinfo add regId:{}, projectId:{}, groupRegist:{},createFlag:{}", regId, projectId, groupRegist, createFlag);

        String studentId = null;
        StudentProject studentProject = new StudentProject();
        if (StringUtils.isNotEmpty(regId)) {
            studentProject = studentProjectMapper.getProjectStudent(projectId, regId);
        }

        String deptId = iBaseLoginService.getDeptId();
        // 获取机构部门的采集字段
        String officeCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.office.getCode(), projectId, DelFlagEnum.NORMAL.getCode());
        // 获取部门的采集值
        Optional<String> deptCollectValueOpt = studentInfos.stream()
                .filter(data -> StrUtil.equals(data.getProjectCollectInfoId(), officeCollectId))
                .map(StudentInfo::getValue)
                .filter(StrUtil::isNotBlank)
                .findAny();
        if (deptCollectValueOpt.isPresent()) {
            deptId = getLastDeptId(deptCollectValueOpt.get());
        }

        // 判断是否新增
        if (studentProject != null && CharSequenceUtil.isNotEmpty(studentProject.getId())) {
            studentId = studentProject.getId();
            studentProject.setUpdateDate(LocalDateTime.now());
            studentProject.setUpdateBy(iBaseLoginService.getUserId());
            studentProject.setIsAudit(Project.getStudentAuditStatus(project.getIsVerify()));
            //加入考生的名字，手机，证件类型，证件号
            ansycStudentInfo(studentInfos, projectId, studentProject);
            studentProject.setDeptId(deptId);
            iStudentProject.updateById(studentProject);
        } else {
            if (studentProject == null) {
                studentProject = new StudentProject();
            }
            studentId = UUIDUtils.newSortUUID();
            studentProject.setId(studentId);
            studentProject.setProjectId(projectId);
            studentProject.setRegId(regId);
            studentProject.setOfficeId(iBaseLoginService.getOfficeId());
            studentProject.setCreateBy(iBaseLoginService.getUserId());
            studentProject.setUpdateBy(iBaseLoginService.getUserId());
            studentProject.setCreateDate(LocalDateTime.now());
            studentProject.setUpdateDate(LocalDateTime.now());
            studentProject.setIsAudit(Project.getStudentAuditStatus(project.getIsVerify()));
            //加入考生的名字，手机，证件类型，证件号
            ansycStudentInfo(studentInfos, projectId, studentProject);
            studentProject.setDeptId(deptId);
            iStudentProject.save(studentProject);

            if (CollectionUtils.isNotEmpty(studentInfos)) {
                List<StudentInfo> studentInfosTemp = new ArrayList<>();
                for (StudentInfo studentInfo : studentInfos) {
                    if (StringUtils.isEmpty(studentInfo.getValue())) {
                        continue;
                    }
                    studentInfo.setProjectId(projectId);
                    studentInfo.setStudentId(studentId);
                    studentInfo.setId(UUIDUtils.newSortUUID());
                    studentInfo.setCreateBy(iBaseLoginService.getUserId());
                    studentInfo.setUpdateBy(iBaseLoginService.getUserId());
                    studentInfo.setCreateDate(LocalDateTime.now());
                    studentInfo.setUpdateDate(LocalDateTime.now());
                    studentInfosTemp.add(studentInfo);
                }
                if (CollectionUtils.isNotEmpty(studentInfosTemp)) {
                    this.saveBatch(studentInfosTemp);
                }
            }
        }

        // 如果是集体报名
        if (groupRegist) {
            // 获取项目所有的科目
            List<ProjectSubject> projectSubjectList = projectSubjectMapper.querySubjectList(projectId, null);
            if (CollUtil.isEmpty(projectSubjectList)) {
                return studentId;
            }

            // 考生科目列表
            List<StudentSubject> studentSubjectList = new ArrayList<>();
            for (ProjectSubject projectSubject : projectSubjectList) {
                // 集体报名默认报考所有科目，这个时候需要将报考的科目和配置的最大报考名额做校验
                Boolean validateStudentSubjectRegistNum = iStudentSubjectService.validateStudentSubjectRegistNum(projectSubject.getProjectId(), projectSubject.getSubjectId());
                if (!validateStudentSubjectRegistNum) {
                    InvalidRequestException.throwException(31081205, "科目配置的报名名额不足，请选择其他科目进行报考！");
                }
                StudentSubject studentSubject = new StudentSubject();
                studentSubject.setSubjectId(projectSubject.getSubjectId());
                studentSubject.setStudentId(studentId);
                studentSubject.setSubjectName(projectSubject.getSubjectName());
                studentSubject.setProjectId(projectId);
                studentSubject.setIsPay(projectSubject.getIsPay());
                studentSubject.setPay(BmPayStatusEnum.UNPAY.getPayStatus());
                studentSubject.setCreateBy(iBaseLoginService.getUserId())
                        .setCreateDate(LocalDateTime.now())
                        .setUpdateBy(iBaseLoginService.getUserId())
                        .setUpdateDate(LocalDateTime.now());
                studentSubjectList.add(studentSubject);
            }

            // 集体报名默认报考所有科目，这个时候需要将报考的科目和项目设置的最大报考科目数做校验
            if (!NumberUtil.equals(project.getMaxSubject(), studentSubjectList.size())) {
                InvalidRequestException.throwException(31081203, "选择的报考科目数量不能大于设置的最多可报考科目数量");
            }

            if (CollectionUtils.isNotEmpty(studentSubjectList)) {
                iStudentSubjectService.saveBatch(studentSubjectList);
            }
        }
        // 创建一个新账号
        if (createFlag) {
            createNewUaAccount(projectId, studentInfos, studentProject, project);
        }
        return studentId;
    }

    /**
     * @return
     */
    private String getLastDeptId(String deptIds) {
        if(StrUtil.isEmptyIfStr(deptIds)) {
            return null;
        }
        List<String> dIds =  StrUtil.split(deptIds, ",");
        return CollUtil.getLast(dIds);
    }

    /**
     * 创建新的账号
     *
     * @param projectId
     * @param list
     * @param entity
     * @param project
     */
    private String createNewUaAccount(String projectId, List<StudentInfo> list, StudentProject entity, Project project) {
        String phone = "";
        String email = "";
        String name = "";
        String deptId = "";
        boolean phoneFlag = false;
        boolean emailFlag = false;
        boolean deptFlag = false;
        String nameId = projectMapper.getCollectIdByProject(ComponentNameEnum.name.getCode(), projectId, DelFlagEnum.NORMAL.getCode());
        String phoneCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.phone.getCode(), projectId, DelFlagEnum.NORMAL.getCode());
        String emailCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.email.getCode(), projectId, DelFlagEnum.NORMAL.getCode());
        String officeCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.office.getCode(), projectId, DelFlagEnum.NORMAL.getCode());
        for (StudentInfo studentInfo : list) {
            if (studentInfo.getProjectCollectInfoId().equals(phoneCollectId)) {
                phoneFlag = true;
                phone = studentInfo.getValue();
            }
            if (studentInfo.getProjectCollectInfoId().equals(emailCollectId)) {
                emailFlag = true;
                email = studentInfo.getValue();
            }
            if (studentInfo.getProjectCollectInfoId().equals(nameId)) {
                name = studentInfo.getValue();
            }
            if (studentInfo.getProjectCollectInfoId().equals(officeCollectId)) {
                deptFlag = true;
                deptId = getLastDeptId(studentInfo.getValue());
            }
        }
        ExamineeRegisterVO examineeRegisterVO = new ExamineeRegisterVO();
        if (!phoneFlag && !emailFlag) {
            throw new InvalidRequestException(31010162, "采集项没有邮箱或者手机号无法生成账号");
        } else {
            if (!deptFlag) {
                deptId = iBaseLoginService.getDeptId();
            }
            if (phoneFlag) {
                examineeRegisterVO.setContent(phone);
                examineeRegisterVO.setName(name);
                examineeRegisterVO.setOfficeid(project.getOfficeId());
                examineeRegisterVO.setDeptId(deptId);
                examineeRegisterVO.setPassword(phone);
            } else {
                if (emailFlag) {
                    examineeRegisterVO.setContent(email);
                    examineeRegisterVO.setName(name);
                    examineeRegisterVO.setOfficeid(project.getOfficeId());
                    examineeRegisterVO.setDeptId(deptId);
                    examineeRegisterVO.setPassword(email);
                }
            }
            try {
                ApiResponse<Object> api = permissionLoginClient.addCandidate(examineeRegisterVO);
                if (api.getCode() == 12001 || api.getCode() == Constant.RESPONSE_CODE_SUCCESS) {
                    String userId = (String) api.getData();
                    entity.setRegId(userId)
                            .setDeptId(deptId);
                    iStudentProject.saveOrUpdate(entity);
                    return userId;
                }
                throw new InvalidRequestException(api.getCode(), "注册账号失败");
            } catch (Exception e) {
                throw new InvalidRequestException(31010161, "注册账号失败");
            }
        }
    }

    @Override
    public List<StudentInfoVo> getByStudentId(String projectId, String studentId) {
        return studentInfoMapper.getByStudentId(projectId, studentId, null);
    }


    @SneakyThrows
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer saveOrUpdateStu(Project project, StudentInfoListVo studentInfoListVo, String active) {
        // 项目ID
        String projectId = project.getId();
        // 考生ID
        String studentId = studentInfoListVo.getStudentId();
        // 获取项目的采集信息维度
        List<ProjectCollectInfoVo> list = iProjectCollectInfoService.queryByProjectId(projectId);

        // 获取考生信息
        StudentProject studentProject = iStudentProject.getById(studentId);
        if (null == studentProject) {
            log.error("# saveOrUpdateStu error, studentProject is null:{}", studentId);
            return Constant.RESPONSE_CODE_31191602;
        }

        List<StudentSubject> studentSubjectList = studentSubjectMapper.getStudentSbjects(studentInfoListVo.getProjectId(), studentInfoListVo.getStudentId());
        if (Constants.PUSH_TYPE_UPDATE.equals(active)) {
            if (null != project && null != project.getIsVerify() && BmProjectVerifyEnum.VERIFY.getVerifyStatus().equals(project.getIsVerify())) {
                // 待审核或审核未通过时，才能修改信息
                if (null != studentProject.getIsAudit() && BmAuditStatusEnum.APPROVED.getAuditStatus().equals(studentProject.getIsAudit())) {
                    return Constant.RESPONSE_CODE_31081201;
                }
                // 如果有审核通过的科目，不允许修改 ————临时讨论的改动
                for (StudentSubject studentSubject : studentSubjectList) {
                    if (null != studentSubject.getIsAudit() && BmAuditStatusEnum.APPROVED.getAuditStatus().equals(studentSubject.getIsAudit())) {
                        return Constant.RESPONSE_CODE_31081201;
                    }
                }
            }
        }

        // 先过滤掉收集信息里面空的数据
        List<StudentInfo> studentInfos = studentInfoListVo.getList();
        for (Iterator<StudentInfo> iterator = studentInfos.iterator(); iterator.hasNext(); ) {
            StudentInfo studentInfo = iterator.next();
            if (StringUtils.isEmpty(studentInfo.getValue())) {
                iterator.remove();
            }
        }
        // 对收集信息的数据进行新增或者修改
        for (StudentInfo studentInfo : studentInfos) {
            String studentProjectCollectInfoId = studentInfo.getProjectCollectInfoId();
            String studentValue = studentInfo.getValue();
            if(CollUtil.isNotEmpty(studentSubjectList)) {
                for (StudentSubject studentSubject : studentSubjectList) {
                    // 校验报名区域的科目名额限制，获取报名区域 studentId
                    String bmAreaCollId = projectMapper.getCollectIdByProject(ProjectSubjectAreaLimit.getBmAreaCollKey(), projectId, DelFlagEnum.NORMAL.getCode());
                    // 获取报名考生数据
                    if (CharSequenceUtil.isNotEmpty(bmAreaCollId) && studentProjectCollectInfoId.equals(bmAreaCollId) && CharSequenceUtil.isNotEmpty(studentValue)) {
                        Boolean checkExcess = iProjectSubjectAreaLimitService.checkExcessBySubjectIdAndArea(projectId, studentId, studentSubject.getSubjectId(), bmAreaCollId, studentValue);
                        if (checkExcess) {
                            InvalidRequestException.throwException(31101203, "您选择的时间段内此科目已报满，请选择其他时间段或科目。");
                        }
                    }
                }
            }
            
            StudentInfo dbStudentInfo = studentInfoMapper.getStudentByCollectId(studentProjectCollectInfoId, studentId, projectId);
            if (dbStudentInfo == null) {
                dbStudentInfo = new StudentInfo();
                dbStudentInfo.setId(UUIDUtils.newSortUUID());
                dbStudentInfo.setStudentId(studentId);
                dbStudentInfo.setProjectCollectInfoId(studentProjectCollectInfoId);
                dbStudentInfo.setValue(studentValue);
                dbStudentInfo.setProjectId(studentInfoListVo.getProjectId());
                dbStudentInfo.setUpdateDate(LocalDateTime.now());
                dbStudentInfo.setUpdateBy(iBaseLoginService.getUserId());
                studentInfoMapper.insert(dbStudentInfo);
            } else {
                dbStudentInfo.setValue(studentValue);
                dbStudentInfo.setUpdateDate(LocalDateTime.now())
                        .setUpdateBy(iBaseLoginService.getUserId());
                studentInfoMapper.updateById(dbStudentInfo);
            }
        }
        // 查询项目下所有的科目
        List<ProjectSubject> projectSubjects = iProjectSubjectService.querySubjectList(projectId, null);
        ProjectStatusAttrDto selectProjectStatusAttrDto = BmBaseService.getSelectProjectStatusAttrDto(projectSubjects, project);
        // 如果项目需要审核修改考生资料提交的状态为待已提交状态
        updateStudentAuditStatus(project, studentInfoListVo, active, studentProject, selectProjectStatusAttrDto);
        //用与更新bm_student_project表的手机号，名字，证件类型，证件号
        StudentProject updateEntity = new StudentProject();
        updateEntity.setId(studentProject.getId());
        ansycStudentInfo(studentInfos, projectId, updateEntity);
        iStudentProject.updateById(updateEntity);
        return Constant.RESPONSE_CODE_SUCCESS;
    }


    /**
     * 如果项目需要审核修改考生的状态为
     *
     * @param project
     * @param studentInfoListVo
     * @param active
     * @param studentProject
     * @param selectProjectStatusAttrDto
     */
    private void updateStudentAuditStatus(Project project, StudentInfoListVo studentInfoListVo, String active, StudentProject studentProject, ProjectStatusAttrDto selectProjectStatusAttrDto) {
        // 如果项目需要审核
        if (null != selectProjectStatusAttrDto.getIsAudit() && BmProjectVerifyEnum.VERIFY.getVerifyStatus().toString().equals(selectProjectStatusAttrDto.getIsAudit())) {
            String bmInformationSubmitAgain = BmAuditInfoSubmitAgainStatus.INIT.getStatus();
            if (BmAuditStatusEnum.UNAPPROVED.getAuditStatus().equals(studentProject.getIsAudit())) {
                bmInformationSubmitAgain = BmAuditInfoSubmitAgainStatus.SUPPLEMENTARY.getStatus();
                StudentVerify sVerify = new StudentVerify();
                // 如果审核不通过状态下修改资料，将审核状态修改为待审核
                sVerify.setVerifyStatus(BmAuditStatusEnum.PENDINGAPPROVAL.getAuditStatus());
                sVerify.setUpdateDate(LocalDateTime.now());
                sVerify.setBmInformationSubmitAgain(bmInformationSubmitAgain);
                sVerify.setStudentId(studentProject.getId());
                sVerify.setProjectId(project.getId());
                sVerify.setVerifyDatetime(LocalDateTime.now());
                studentVerifyMapper.updateAudit(sVerify);
            }
        }
    }

    private String getAreaCascaderId(List<ProjectCollectInfoVo> list) {
        String cascaderId = StringUtils.EMPTY;
        for (int i = 0; i < list.size(); i++) {
            if (ComponentNameEnum.area.getCode().equals(list.get(i).getComponentName())) {
                cascaderId = list.get(i).getId();
            }
        }
        return cascaderId;
    }


    /**
     * 考生的项目科目报考情况查询
     *
     * @param projectId
     * @param regId
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    @Override
    public StudentProjectInfoVo getProjectSubjectById(String projectId, String regId) {
        StudentProjectInfoVo studentProjectInfoVo = new StudentProjectInfoVo();
        // 项目信息
        Project project = projectMapper.selectById(projectId);
        studentProjectInfoVo.setProjectInfo(project);
        // 报名情况
        StudentProject studentProject = studentProjectMapper.getProjectStudent(projectId, regId);
        if (studentProject == null) {
            studentProjectInfoVo.setBmStatus(BmStatusEnum.UNSIGNUP.getSignStatus());
            studentProjectInfoVo.setBmStatusDesc(BmStatusEnum.UNSIGNUP.getMsg());
        } else {
            studentProjectInfoVo.setBmStatus(BmStatusEnum.SIGNUP.getSignStatus());
            studentProjectInfoVo.setBmStatusDesc(BmStatusEnum.SIGNUP.getMsg());
            studentProjectInfoVo.setStudentId(studentProject.getId());
            // 获取考生的报考科目
            List<StudentSubject> subjectList = iStudentSubjectService.queryRegSubject(StrUtil.isNotBlank(regId) ? regId : "-1", projectId);
            // 如果已经存在报考科目，怎显示考生的审核状态
            if (CollUtil.isNotEmpty(subjectList)) {
                studentProjectInfoVo.setIsAudit(studentProject.getIsAudit());
            }

            //考生是否已填写基本信息
            List<StudentInfoVo> studentInfoVoList = this.getByStudentId(projectId, studentProject.getId());
            studentProjectInfoVo.setHasStudentInfo(CollUtil.isNotEmpty(studentInfoVoList) ? 1 : 0);
        }
        // 查询考生科目列表
        List<ProjectSubject> projectSubjects = projectSubjectMapper.getSubjectList(projectId, regId, null);
        List<ProjectSubjectVo> projectSubjectVos = new ArrayList<>();

        if (CollectionUtils.isNotEmpty(projectSubjects)) {
            for (ProjectSubject projectSubjectOrg : projectSubjects) {
                ProjectSubjectVo projectSubjectVo = new ProjectSubjectVo();
                projectSubjectVo.setProjectSubjectStatusDesc("未报考"); // 初始状态
                BeanUtils.copyProperties(projectSubjectOrg, projectSubjectVo);
                projectSubjectVos.add(projectSubjectVo);
            }
        }
        if (null != studentProject && CollectionUtils.isNotEmpty(projectSubjectVos)) {
            // 获取考生报名科目列表
            List<StudentSubject> studentSubjects = studentSubjectMapper.getStudentSbjects(projectId, studentProject.getId());
            //考生在这个项目上的报名支付状态（小程序用）
            this.studentProjectPayStatus(studentProjectInfoVo, studentSubjects);
            Map<String, StudentSubject> studentSubjectMap = new HashMap<>();
            if (CollectionUtils.isNotEmpty(projectSubjectVos)) {
                for (StudentSubject studentSubjectTemp : studentSubjects) {
                    studentSubjectMap.put(studentSubjectTemp.getSubjectId(), studentSubjectTemp);
                    for (ProjectSubjectVo vo : projectSubjectVos) {
                        //报名时间
                        if (vo.getSubjectId().equals(studentSubjectTemp.getSubjectId())) {
                            if (null == studentSubjectTemp.getBmTime() && Objects.equals(studentSubjectTemp.getPay(), BmPayStatusEnum.PAY.getPayStatus())) {
                                vo.setBmTime(studentSubjectTemp.getUpdateDate());
                            }
                        }
                    }
                }
            }


            for (int i = 0; i < projectSubjectVos.size(); i++) {
                ProjectSubjectVo projectSubject = projectSubjectVos.get(i);
                if (projectSubject.getStatus().equals("0")) {
                    this.setAllowReg(projectSubject);
                    continue;
                }
                projectSubject.setIsAudit(studentProject.getIsAudit());
                //设置科目自己的审核状态
                StudentSubject studentSubjectTemp = studentSubjectMap.get(projectSubject.getSubjectId());
                if (null != studentSubjectTemp && null != studentSubjectTemp.getIsAudit()) {
                    projectSubject.setIsAudit(studentSubjectTemp.getIsAudit());
                }
                if (BmAuditStatusEnum.APPROVED.getAuditStatus().equals(studentProject.getIsAudit())) {
                    // 需要缴费,这个修改为考试科目是否需要缴费
                    this.approvedStudentProject(studentProjectInfoVo, projectSubject, studentSubjectTemp);
                } else if (BmAuditStatusEnum.UNAPPROVED.getAuditStatus().equals(studentProject.getIsAudit())) {
                    this.unapprovedStudentProject(studentProjectInfoVo, projectSubject, studentSubjectTemp);
                } else {
                    if (project.getIsVerify() == 1) {
                        this.pendingapprovalStudentProject(studentProjectInfoVo, projectSubject, studentSubjectTemp);
                    } else {
                        this.approvedStudentProject(studentProjectInfoVo, projectSubject, studentSubjectTemp);
                        //有报考科目，不需要审核，直接审核通过
                        studentProjectInfoVo.setIsAudit(1);
                        projectSubject.setIsAudit(1);
                        projectSubject.setAuditStatusDesc("无需审核");
                        projectSubject.setProjectSubjectCancel(Boolean.FALSE);
                    }
                }
                // 如果已经报名科目是已经缴费
                StudentSubject studentSubject = studentSubjectMap.get(projectSubject.getSubjectId());
                if (null != studentSubject && studentSubject.getPay().equals(BmPayStatusEnum.PAY.getPayStatus())) {
                    projectSubject.setProjectSubjectStatusDesc("报考成功");
                    if (null == studentSubject.getBmTime()) {
                        projectSubject.setBmTime(studentSubject.getUpdateDate());
                    } else {
                        projectSubject.setBmTime(studentSubject.getBmTime());
                    }
                }
                this.setAllowReg(projectSubject);

            }
        }
        studentProjectInfoVo.setStudentSubjectList(projectSubjectVos);
        return studentProjectInfoVo;
    }

    /**
     * 设置是否可以报考标识
     *
     * @param projectSubject
     */
    private void setAllowReg(ProjectSubjectVo projectSubject) {
        // 当前科目是否可以报考，主要是看科目的目前总报名人数 < 科目设置的最大报考人数
        // 1、获取科目的最大报考人数
        Integer maxNumberofRegister = projectSubject.getMaxNumberofRegister();
        // 2、 查询当前科目已报考人数，不管审核通过或者不通过
        // 获取每一个科目的实际报考数量
        Integer countStudentSubject = studentSubjectMapper.countStudentSubject(projectSubject.getProjectId(), projectSubject.getSubjectId());
        if (maxNumberofRegister.compareTo(0) > 0 && countStudentSubject.compareTo(maxNumberofRegister) >= 0) {
            projectSubject.setAllowReg(Boolean.FALSE);
        }

    }


    /**
     * @Params:
     * @Description: 考生在这个项目上的报名支付状态（小程序用）
     * @Author: STARF
     * @CreateDate: 报名状态（0-未缴费，1-部分缴费，2-已缴费，3-部分退费，4-已退费）"
     **/
    private void studentProjectPayStatus(StudentProjectInfoVo studentProjectInfoVo, List<StudentSubject> studentSubjects) {
        if (null == studentProjectInfoVo) {
            return;
        }
        // 需要缴费的科目数量
        int needPaySubjectCount = 0;
        // 已经缴费的科目数量
        int paySubjectCount = 0;
        // 退费的科目数量
        int refundSubjectCount = 0;

        for (StudentSubject studentSubject : studentSubjects) {
            if (BmProjectNeedPayEnum.PAY.getPayStatus().equals(studentSubject.getIsPay())) {
                needPaySubjectCount += 1;
                if (BmPayStatusEnum.PAY.getPayStatus().equals(studentSubject.getPay()) || BmPayStatusEnum.REFUND_FAIL.getPayStatus().equals(studentSubject.getPay())) {
                    paySubjectCount += 1;
                }
                if (BmPayStatusEnum.REFUND_SUCEESS.getPayStatus().equals(studentSubject.getPay())) {
                    refundSubjectCount += 1;
                }
            }
        }

        // 默认已缴费
        int payStatus = 2;

        // 如果有退费，退费数量=需要缴费数量，显示已退费
        if (0 < refundSubjectCount && refundSubjectCount == needPaySubjectCount) {
            payStatus = 4;
        }

        // 如果有退费，退费数量小于需要缴费数量，显示部分退费
        if (0 < refundSubjectCount && refundSubjectCount < needPaySubjectCount) {
            payStatus = 3;
        }

        // 如果没有退费，有缴费科目， 缴费数量等于需要缴费数量，显示已缴费
        if (0 == refundSubjectCount && 0 < paySubjectCount && paySubjectCount == needPaySubjectCount) {
            payStatus = 2;
        }

        // 如果没有退费，有缴费科目， 缴费数量小于需要缴费数量，显示部分缴费
        if (0 == refundSubjectCount && 0 < paySubjectCount && paySubjectCount < needPaySubjectCount) {
            payStatus = 1;
        }

        // 没有退费，没有缴费，就是未缴费
        if (0 == refundSubjectCount && 0 == paySubjectCount) {
            payStatus = 0;
        }

        // 没有需要缴费就是已缴费
        if (0 == needPaySubjectCount) {
            payStatus = 2;
        }
        studentProjectInfoVo.setPayStatus(payStatus);
    }

    /**
     * @Params:
     * @Description: 审核通过时，报名状态设置
     * @Author: STARF
     * @CreateDate: 2022/3/29 10:52
     **/
    private void approvedStudentProject(StudentProjectInfoVo studentProjectInfoVo, ProjectSubjectVo projectSubject, StudentSubject studentSubject) {
        if (projectSubject.getIsPay() == 1) {
            if (BmPayStatusEnum.UNPAY.getPayStatus().toString().equals(projectSubject.getPayStatus())) {
                projectSubject.setAudit(BmPayStatusEnum.UNPAY.getMsg());
                studentProjectInfoVo.setBmStatusDesc(BmPayStatusEnum.UNPAY.getMsg());
                projectSubject.setProjectSubjectStatusDesc(BmAuditStatusEnum.APPROVED.getMsg());
            }
            if (BmPayStatusEnum.REFUND_SUCEESS.getPayStatus().toString().equals(projectSubject.getPayStatus())) {
                projectSubject.setAudit(BmPayStatusEnum.UNPAY.getMsg());
                studentProjectInfoVo.setBmStatusDesc(BmPayStatusEnum.REFUND_SUCEESS.getMsg());
                projectSubject.setProjectSubjectStatusDesc(BmAuditStatusEnum.APPROVED.getMsg());
            } else if (BmPayStatusEnum.PAY.getPayStatus().toString().equals(projectSubject.getPayStatus())) {
                projectSubject.setAudit("报考成功");
                studentProjectInfoVo.setBmStatusDesc("报考成功");
                projectSubject.setProjectSubjectStatusDesc("报考成功");
            }
        } else {
            projectSubject.setAudit("报考成功");
            studentProjectInfoVo.setBmStatusDesc("报考成功");
            projectSubject.setProjectSubjectStatusDesc("报考成功");
            projectSubject.setPayStatus("1");
        }
        projectSubject.setProjectSubjectCancel(Boolean.FALSE);
        if ("报考成功".equals(projectSubject.getAudit()) && null != studentSubject) {
            if (null == studentSubject.getBmTime()) {
                projectSubject.setBmTime(studentSubject.getUpdateDate());
            } else {
                projectSubject.setBmTime(studentSubject.getBmTime());
            }
        }
    }

    /**
     * @Params:
     * @Description: 待审核时，报名状态设置
     * @Author: STARF
     * @CreateDate: 2022/3/29 10:52
     **/
    private void pendingapprovalStudentProject(StudentProjectInfoVo studentProjectInfoVo, ProjectSubjectVo projectSubject, StudentSubject studentSubject2) {
        studentProjectInfoVo.setBmStatusDesc("已报考-待审核");
        if (null != studentSubject2 && null != studentSubject2.getIsAudit()) {
            if (BmAuditStatusEnum.UNAPPROVED.getAuditStatus().equals(studentSubject2.getIsAudit())) {
                projectSubject.setAudit(BmAuditStatusEnum.UNAPPROVED.getMsg());
                projectSubject.setProjectSubjectStatusDesc(BmAuditStatusEnum.UNAPPROVED.getMsg());
            } else if (BmAuditStatusEnum.APPROVED.getAuditStatus().equals(studentSubject2.getIsAudit())) {
                projectSubject.setAudit(BmAuditStatusEnum.APPROVED.getMsg());
                projectSubject.setProjectSubjectStatusDesc(BmAuditStatusEnum.APPROVED.getMsg());
            } else {
                projectSubject.setAudit(BmAuditStatusEnum.PENDINGAPPROVAL.getMsg());
                projectSubject.setProjectSubjectStatusDesc(BmAuditStatusEnum.PENDINGAPPROVAL.getMsg());
            }
        }

        // 如果审核不通过单科目已经缴费则不能取消，覆盖上面的状态
        if (projectSubject.getIsPay() == 1) {
            if (BmPayStatusEnum.PAY.getPayStatus().equals(projectSubject.getPayStatus())) {
                projectSubject.setProjectSubjectCancel(Boolean.FALSE);
            }
        }
    }

    /**
     * @Params:
     * @Description: 审核不通过时，报名状态设置
     * @Author: STARF
     * @CreateDate: 2022/3/29 10:52
     **/
    private void unapprovedStudentProject(StudentProjectInfoVo studentProjectInfoVo, ProjectSubjectVo projectSubject, StudentSubject studentSubject2) {
        projectSubject.setAudit(BmAuditStatusEnum.UNAPPROVED.getMsg());
        studentProjectInfoVo.setBmStatusDesc(BmAuditStatusEnum.UNAPPROVED.getMsg());
        projectSubject.setProjectSubjectStatusDesc(BmAuditStatusEnum.UNAPPROVED.getMsg());
        if (null != studentSubject2 && null != studentSubject2.getIsAudit()) {
            if (studentSubject2.getIsAudit() == 0) {
                projectSubject.setAudit(BmAuditStatusEnum.PENDINGAPPROVAL.getMsg());
                projectSubject.setProjectSubjectStatusDesc(BmAuditStatusEnum.PENDINGAPPROVAL.getMsg());
            } else if (studentSubject2.getIsAudit() == 1) {
                projectSubject.setAudit(BmAuditStatusEnum.APPROVED.getMsg());
                projectSubject.setProjectSubjectStatusDesc(BmAuditStatusEnum.APPROVED.getMsg());
            }
        }
        // 如果审核不通过单科目已经缴费则不能取消，覆盖上面的状态
        if (projectSubject.getIsPay() == 1) {
            if (BmPayStatusEnum.PAY.getPayStatus().equals(projectSubject.getPayStatus())) {
                projectSubject.setProjectSubjectCancel(Boolean.FALSE);
            }
        }
        // 不通过原因
        projectSubject.setAuditResult(projectSubjectMapper.getResultByStudent(projectSubject.getProjectId(), projectSubject.getStudentId()));
    }

    /**
     * @Params:
     * @Description: 考生的项目及其科目的考试状态设置
     * @Author: STARF
     * @CreateDate: 2022/3/29 11:06
     **/
    @SuppressWarnings("unchecked")
    private void studentProjectKsStatus(StudentProjectInfoVo studentProjectInfoVo, ProjectSubjectVo projectSubject, Map<String, Object> map) {
        Integer codeString = (Integer) map.get("code");
        // 考务数据同步查询
        if (codeString == 16001) {
            Map<String, Object> mapObj = (Map<String, Object>) map.get("data");
            Integer examState = (Integer) mapObj.get("examState");
            String beginDate = (String) mapObj.get("beginDate");
            String endDate = (String) mapObj.get("endDate");
            boolean publishResult = (boolean) mapObj.get("publishResult");
            if (examState == 1) {
                projectSubject.setKsStatus("考试中");
                studentProjectInfoVo.setBmStatusDesc("考试中");
                projectSubject.setProjectSubjectStatusDesc("考试中");
            } else if (examState == 2) {
                projectSubject.setKsStatus("考试-已过期");
                studentProjectInfoVo.setBmStatusDesc("考试-已过期");
                projectSubject.setProjectSubjectStatusDesc("考试-已过期");
            } else if (examState == 3) {
                projectSubject.setKsStatus("考试-未开始");
                studentProjectInfoVo.setBmStatusDesc("考试-未开始");
                projectSubject.setProjectSubjectStatusDesc("考试-未开始");
            }
            if (publishResult) {
                projectSubject.setKsStatus("考试结束");
                studentProjectInfoVo.setBmStatusDesc("考试结束");
                projectSubject.setProjectSubjectStatusDesc("考试结束,成绩已发布");
                projectSubject.setCjStatus("成绩-已发布");
            } else {
                projectSubject.setCjStatus("成绩-未发布");
                if (examState != 1 && examState != 2 && examState != 3) {
                }
            }

            projectSubject.setKsBeginDate(beginDate);
            projectSubject.setKsEndDate(endDate);
        } else {
            projectSubject.setKsStatus("考试-未开始");
            projectSubject.setCjStatus("成绩-未发布");
            studentProjectInfoVo.setBmStatusDesc("考试-未开始");
            projectSubject.setProjectSubjectStatusDesc("考试-未开始");
        }
    }

    @Override
    public List<StudentVo> queryStudentList(StudentParam studentParam, List<String> permissionList, long current, long size) {
        List<StudentVo> list = studentInfoMapper.queryStudentList(studentParam, permissionList, current, size);
        return list;
    }

    @Override
    public long queryStudentListCount(StudentParam studentParam, List<String> permissionList) {

        return studentInfoMapper.queryStudentListCount(studentParam, permissionList);
    }

    @SuppressWarnings("unchecked")
    @Override
    public StudentDetail getStudentInfo(String projectId, String studentId) {
        StudentDetail studentDetail = new StudentDetail();
        studentDetail.setProjectId(projectId);
        studentDetail.setStudentId(studentId);
        StudentVo stuList = studentInfoMapper.getStuInfoByStudentId(projectId, studentId);

        String studentInfoPhoto = this.getStudentInfoPhoto(projectId, studentId, stuList.getPhoto());
        stuList.setPhoto(studentInfoPhoto);

        // 考生信息
        studentDetail.setStuList(stuList);
        // 考生审核状态
        Integer isAudit = studentInfoMapper.getAuditByStudentId(studentId);

        List<StudentSubjectDetailVo> subjectList = projectSubjectMapper.getProjectSubjectByStuId(projectId, studentId);
        try {
            for (int i = 0; i < subjectList.size(); i++) {
                if (null == subjectList.get(i).getIsAudit()) {
                    subjectList.get(i).setAuditStatus(isAudit);
                } else {
                    subjectList.get(i).setAuditStatus(subjectList.get(i).getIsAudit());
                }
            }
        } catch (Exception e) {
            log.error("# getStudentInfo error", e);
        }
        // 考生报名科目信息
        studentDetail.setSubjectList(subjectList);
        return studentDetail;
    }

    /**
     * 获取学生的身份证照没拿到的情况下更换证件照
     *
     * @param projectId
     * @param studentId
     * @param photo
     * @return
     */
    private String getStudentInfoPhoto(String projectId, String studentId, String photo) {
        List<String> studentInfoPhotoList = StrUtil.split(photo, ",");
        photo = studentInfoPhotoList.stream()
                .findFirst()
                .orElse(null);

        if (StrUtil.isBlank(photo)) {
            ProjectCollectInfo certificatephoto = iProjectCollectInfoService.lambdaQuery()
                    .eq(ProjectCollectInfo::getProjectId, projectId)
                    .eq(ProjectCollectInfo::getComponentName, "certificatephoto")
                    .one();
            if (certificatephoto != null) {
                StudentInfo studentCertificatephoto = studentInfoMapper.getStudentByCollectId(certificatephoto.getId(), studentId, projectId);
                if (studentCertificatephoto != null) {
                    String certificatephotoValue = studentCertificatephoto.getValue();
                    List<String> certificatephotos = StrUtil.split(certificatephotoValue, ",");
                    photo = CollUtil.getFirst(certificatephotos);
                }
            }
        }

        return photo;
    }

    @Override
    public void export(HttpServletResponse response, List<String> permissionList, StudentParam studentParam) {
        Project project = projectMapper.selectById(studentParam.getProjectId());
        Date date = new Date();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
        String dateString = formatter.format(date);
        String title = dateString + "-" + project.getProjectName() + "-考生详情";
        String titleColumn = projectMapper.getTitleColumn(studentParam.getProjectId());
        String titleString = "student_id,create_date,is_audit,subject_name," + titleColumn;
        String[] titleColumns = titleString.split(",");
        QueryWrapper<ProjectCollectInfo> wrapper = new QueryWrapper<ProjectCollectInfo>();
        wrapper.eq("project_id", studentParam.getProjectId());
        wrapper.orderByAsc("order_num");
        String titleNameString = "考生id, 报名时间, 是否审核,科目," + titleColumn;
        String[] titleName = titleNameString.split(","); // 表头，列名

        int[] array = new int[titleColumns.length];
        for (int i = 0; i < array.length; i++) {
            array[i] = TITLE_SIZE;
        }
        // 动态生成列SQL
        String columns = projectSubjectMapper.getTitleSqlColumn(studentParam.getProjectId());
        // 查询考生信息列表
        List<Map<String, Object>> listMaps = projectSubjectMapper.getAllSubjectList(columns,
                studentParam.getProjectId(), permissionList, studentParam.getSubjectId(), studentParam.getKeyWord());

        excelExport.exportMapExcel(response, title, titleColumns, titleName, array, listMaps);
    }

    @SneakyThrows
    @Override
    public void zip(HttpServletResponse response, List<String> permissionList, StudentParam studentParam) {
        String title = "考生数据";
        String titleColumn = StringUtils.EMPTY;
        String bmlistexportbase = configManager.getBmlistExportBaseInfo();
        if (StringUtils.isNotEmpty(bmlistexportbase) && Boolean.valueOf(bmlistexportbase)) {
            titleColumn = projectMapper.getBaseTitleColumn(studentParam.getProjectId());
        }
        if (StringUtils.isNotEmpty(bmlistexportbase) && Boolean.valueOf(bmlistexportbase)) {
            titleColumn = projectMapper.getTitleColumn(studentParam.getProjectId());
        }
        String titleString = "student_id,subject_name," + titleColumn;
        String[] titleColumns = titleString.split(",");

        List<ProjectCollectInfo> list = iProjectCollectInfoService.getProjectCollectInfosByPid(studentParam.getProjectId());

        String titleNameString = "考生id, 科目," + titleColumn;
        String[] titleName = titleNameString.split(","); // 表头，列名
        String typeColums = "input,input,";
        for (ProjectCollectInfo projectCollectInfo : list) {
            typeColums += projectCollectInfo.getComponentType() + ",";
        }
        if (StringUtils.isNotBlank(typeColums)) {
            typeColums = typeColums.substring(0, typeColums.length() - 1);
        }
        // 采集信息有选项的数据集合
        Map<String, List<ProjectCollectInfoOption>> optionMap = new HashMap<String, List<ProjectCollectInfoOption>>();
        Map<String, List<ProjectCollectInfoOption>> optionMapTemp = iProjectCollectInfoOptionService.getOptionListMap(studentParam.getProjectId());
        for (ProjectCollectInfo projectCollectInfo : list) {
            typeColums += projectCollectInfo.getComponentType() + ",";
            if (ComponentTypeEnum.componentTypeHasOption(projectCollectInfo.getComponentType())) {
                List<ProjectCollectInfoOption> optionList = optionMapTemp.get(projectCollectInfo.getId());
                if (CollectionUtils.isNotEmpty(optionList)) {
                    optionMap.put(projectCollectInfo.getTitle(), optionList);
                }
            }
        }


        int[] array = new int[titleColumns.length];
        for (int i = 0; i < array.length; i++) {
            array[i] = TITLE_SIZE;
        }
        // 动态生成列SQL
        String columns = projectSubjectMapper.getTitleSqlColumn(studentParam.getProjectId());
        if (StringUtils.isEmpty(columns)) {
            throw new RuntimeException("根据项目id查询不到采集信息");
        }
        // 查询考生信息列表
        List<Map<String, Object>> listMaps = projectSubjectMapper.getAllSubjectList(columns,
                studentParam.getProjectId(), permissionList, studentParam.getSubjectId(), studentParam.getKeyWord());
        for (int i = 0; i < listMaps.size(); i++) {
            Map<String, Object> obj = listMaps.get(i);
            for (Map.Entry<String, Object> entry : obj.entrySet()) {
                if (entry.getKey().equals(ComponentNameEnum.office.getDesc()) && entry.getValue().toString().contains("[")) {
                    JSONArray arr = JSONArray.parseArray(entry.getValue().toString());
                    String str = "";
                    for (int l = 0; l < arr.size(); l++) {
                        str = str + "," + arr.getString(l);
                    }
                    entry.setValue(str.substring(1));
                }
            }
            for (int columnIndex = 0; columnIndex < titleName.length; columnIndex++) {
                String column = titleName[columnIndex].trim();
                List<ProjectCollectInfoOption> optionList = optionMap.get(column);
                if (optionList != null && optionList.size() > 0) {
                    if (StringUtils.isNotBlank(columns)) {
                        String data = obj.get(column) == null ? "" : obj.get(column).toString();
                        String dataStr[] = data.split(",");
                        if (dataStr != null && dataStr.length > 0) {
                            String columnstr = "";
                            for (int m = 0; m < dataStr.length; m++) {
                                for (int j = 0; j < optionList.size(); j++) {
                                    if (dataStr[m].equals(optionList.get(j).getOptionValue())) {
                                        columnstr += optionList.get(j).getOptionLabel() + ",";
                                        break;
                                    }
                                }
                            }
                            if (StringUtils.isNotBlank(columnstr)) {
                                columnstr = columnstr.substring(0, columnstr.length() - 1);
                            }
                            obj.put(column, columnstr);
                        }
                    }
                }
            }
        }
        excelExport.zipMapExcel(response, title, titleColumns, titleName, typeColums.split(","), array, listMaps);
    }

    @Override
    public void exportStudentList(HttpServletResponse response, StudentInfoParam param) throws Exception {
        String projectId = param.getProjectId();
        String exportFileName = this.getExportFileName(projectId);
        log.info("# 11.1.7 管理端：导出考生列表title: {}", exportFileName);
        String titleColumn = getTitleColumn(param.getProjectId());
        log.info("# 11.1.7 管理端：导出考生列表titleColumn={}", titleColumn);
        String titleString = "num,createDate," + titleColumn;
        String[] titleColumns = titleString.split(",");

        List<ProjectCollectInfo> list = iProjectCollectInfoService.getProjectCollectInfosByPid(param.getProjectId());

        String titleNameString = "报考科目数, 报名时间," + titleColumn;
        String[] titleName = titleNameString.split(","); // 表头，列名
        StringBuilder typeColums = new StringBuilder();
        typeColums.append("input,date,");

        // 采集信息有选项的数据集合
        Map<String, List<ProjectCollectInfoOption>> optionMap = new HashMap<String, List<ProjectCollectInfoOption>>();
        Map<String, List<ProjectCollectInfoOption>> optionMapTemp = iProjectCollectInfoOptionService.getOptionListMap(param.getProjectId());
        for (ProjectCollectInfo projectCollectInfo : list) {
            typeColums.append(projectCollectInfo.getComponentType());
            typeColums.append(",");
            if (ComponentTypeEnum.componentTypeHasOption(projectCollectInfo.getComponentType())) {
                List<ProjectCollectInfoOption> optionList = optionMapTemp.get(projectCollectInfo.getId());
                if (CollectionUtils.isNotEmpty(optionList)) {
                    optionMap.put(projectCollectInfo.getTitle(), optionList);
                }
            }
        }

        if (StringUtils.isNotBlank(typeColums)) {
            typeColums = typeColums.deleteCharAt(typeColums.length() - 1);
        }
        int[] array = new int[titleColumns.length];
        for (int i = 0; i < array.length; i++) {
            array[i] = TITLE_SIZE;
        }
        // 动态生成列SQL
        String columns = projectSubjectMapper.getTitleSqlColumn(projectId);
        List<String> studentIds = new ArrayList<>();
        // 查询考生信息列表
        if (!StringUtils.isEmpty(param.getStudentIds())) {
            for (int i = 0; i < param.getStudentIds().split(",").length; i++) {
                studentIds.add(param.getStudentIds().split(",")[i]);
            }
        }
        param.setColumns(columns);
        param.setIds(studentIds);
        param.setSize(-1);
        List<Map<String, Object>> listMaps = projectSubjectMapper.getAllList(param);

        for (int i = 0; i < listMaps.size(); i++) {
            Map<String, Object> obj = listMaps.get(i);
            for (Map.Entry<String, Object> entry : obj.entrySet()) {
                if (entry.getKey().equals(ComponentNameEnum.office.getDesc()) && entry.getValue().toString().contains("[")) {
                    JSONArray arr = JSONArray.parseArray(entry.getValue().toString());
                    String str = "";
                    for (int l = 0; l < arr.size(); l++) {
                        str = str + "," + arr.getString(l);
                    }
                    entry.setValue(str.substring(1));
                }
            }
            for (int columnIndex = 0; columnIndex < titleName.length; columnIndex++) {
                String column = titleName[columnIndex].trim();
                List<ProjectCollectInfoOption> optionList = optionMap.get(column);
                if (optionList != null && optionList.size() > 0) {
                    if (StringUtils.isNotBlank(columns)) {
                        String data = obj.get(column) == null ? "" : obj.get(column).toString();
                        String dataStr[] = data.split(",");
                        if (dataStr != null && dataStr.length > 0) {
                            String columnstr = "";
                            for (int m = 0; m < dataStr.length; m++) {
                                for (int j = 0; j < optionList.size(); j++) {
                                    if (dataStr[m].equals(optionList.get(j).getOptionValue())) {
                                        columnstr += optionList.get(j).getOptionLabel() + ",";
                                        break;
                                    }
                                }
                            }
                            if (StringUtils.isNotBlank(columnstr)) {
                                columnstr = columnstr.substring(0, columnstr.length() - 1);
                            }
                            obj.put(column, columnstr);
                        }
                    }
                }
            }
        }
        log.info("# 11.1.7 管理端：导出考生列表listMaps-002={}", FastJsonUtil.getBeanToJson(listMaps));
        String urlLink = configManager.getBmlistExportUrlLinkInfo();
        String zipUrl = uploadFileToHuaweiUtil.zipMapExcelUploadToHuaWei(exportFileName + ".zip", titleColumns, titleName, typeColums.toString().split(","), array, listMaps, Boolean.valueOf(urlLink));
        log.info("exportStudentList: zipUrl=" + zipUrl);
        response.sendRedirect(zipUrl);
    }


    private String getTitleColumn(String projectId) {
        String titleColumn = StringUtils.EMPTY;
        String bmlistexportbase = configManager.getBmlistExportBaseInfo();
        if (StringUtils.isNotEmpty(bmlistexportbase) && Boolean.valueOf(bmlistexportbase)) {
            titleColumn = projectMapper.getBaseTitleColumn(projectId);
        } else {
            titleColumn = projectMapper.getTitleColumn(projectId);
        }
        return titleColumn;
    }

    private String getExportColumns(String projectId) {
        String bmlistexportbase = configManager.getBmlistExportBaseInfo();
        String columns = StringUtils.EMPTY;
        if (StringUtils.isNotEmpty(bmlistexportbase) && Boolean.valueOf(bmlistexportbase)) {
            columns = projectSubjectMapper.getBaseInfoTitleSqlColumn(projectId);
        } else {
            columns = projectSubjectMapper.getTitleSqlColumn(projectId);
        }
        return columns;
    }

    public String exportStudentList(StudentInfoParam param) {
        String projectId = param.getProjectId();
        // 构建导出表的名称
        String exportFileName = this.getExportFileName(projectId);

        log.info("# 11.1.7 管理端：导出考生列表exportFileName:{}", exportFileName);
        String titleColumn = getTitleColumn(projectId);
        log.info("# 11.1.7 管理端：导出考生列表titleColumn={}", titleColumn);
        List<String> titleColumnList = new ArrayList<>();
        titleColumnList.add("报考科目");
        titleColumnList.add("报考时间");
        titleColumnList.addAll(Arrays.asList(titleColumn.split(",")));
        // 构建动态表头
        List<List<String>> headList = new ArrayList<>();
        titleColumnList.forEach(dsata -> {
            List<String> tempHead = new ArrayList<>();
            tempHead.add(dsata);
            headList.add(tempHead);
        });


        ProgressManager.updateProgressCurrent(20L, null);
        log.info("## 导出学生完成 %{}", 20L);

        // 动态生成列SQL
        String columns = getExportColumns(projectId);
        ProgressManager.updateProgressCurrent(30L, null);
        log.info("## 导出学生完成 %{}", 30L);
        List<Map<String, Object>> listMaps = new ArrayList<>();
        List<String> studentIds = new ArrayList<>();
        if(param.getStudentHasBmSubject()) {
            // 查询考生信息列表
            if (StringUtils.isNotEmpty(param.getStudentIds())) {
                for (int i = 0; i < param.getStudentIds().split(",").length; i++) {
                    studentIds.add(param.getStudentIds().split(",")[i]);
                }
            }
            param.setColumns(columns);
            param.setIds(studentIds);
            ProgressManager.updateProgressCurrent(35L, null);
            log.info("## 导出学生完成 %{}", 35L);
            param.setSize(-1);
            listMaps = projectSubjectMapper.getAllList(param);
        } else {
            studentIds = getNoSubjectStudentIds(projectId);
            param.setColumns(columns);
            param.setIds(studentIds);
            ProgressManager.updateProgressCurrent(35L, null);
            log.info("## 导出学生完成 %{}", 35L);
            param.setSize(-1);
            listMaps = projectSubjectMapper.getAllListNoSubject(param);
        }
        ProgressManager.updateProgressCurrent(55L, null);
        log.info("## 导出学生完成 %{}", 55L);
        // 转换数据
        List<StudentSubjectExportVo> studentSubjectExportVos = iStudentSubjectService.getStudentSubjectNamesByProjectId(projectId);
        Map<String, String> studentSubjectMap = new HashMap<>();
        if (CollUtil.isNotEmpty(studentSubjectExportVos)) {
            for (StudentSubjectExportVo studentSubjectExportVo : studentSubjectExportVos) {
                studentSubjectMap.put(studentSubjectExportVo.getStudentId(), studentSubjectExportVo.getSubjectNames());
            }
        }
        ProgressManager.updateProgressCurrent(60L, null);
        log.info("## 导出学生完成 %{}", 60L);
        List<List<String>> listTemp = convertListMaps(projectId, listMaps, titleColumnList, studentSubjectMap);
        ProgressManager.updateProgressCurrent(80L, null);
        log.info("## 导出学生完成 %{}", 80L);


        String zipUrl = uploadFileToHuaweiUtil.zipMapExcelUploadToHuaWeiV2(exportFileName + ".zip", projectId, headList, listTemp);
        log.info("exportStudentList: zipUrl：{}", zipUrl);
        ProgressManager.finish(zipUrl);
        log.info("## 导出学生完成 %{}", 100L);
        return zipUrl;
    }


    /**
     * //TODO 添加方法功能描述
     * @param projectId
     * @return
     */
    private List<String> getNoSubjectStudentIds(String projectId) {
        // 获取没有报考科目的考生集合
        List<String> studendIds = studentInfoMapper.getNoSubjectStudentIds(projectId);
        return studendIds;
    }

    /**
     * 转换数据
     *
     * @param listMaps
     */
    private List<List<String>> convertListMaps(String projectId, List<Map<String, Object>> listMaps, List<String> titleColumnList, Map<String, String> studentSubjectMap) {
        // 采集信息有选项的数据集合
        List<List<String>> dataResult = new ArrayList<>();
        Map<String, List<ProjectCollectInfoOption>> optionMap = new HashMap<>();
        Map<String, List<ProjectCollectInfoOption>> optionMapTemp = iProjectCollectInfoOptionService.getOptionListMap(projectId);
        List<ProjectCollectInfo> list = iProjectCollectInfoService.getProjectCollectInfosByPid(projectId);
        for (ProjectCollectInfo projectCollectInfo : list) {
            if (ComponentTypeEnum.componentTypeHasOption(projectCollectInfo.getComponentType())) {
                List<ProjectCollectInfoOption> optionList = optionMapTemp.get(projectCollectInfo.getId());
                if (CollectionUtils.isNotEmpty(optionList)) {
                    optionMap.put(projectCollectInfo.getTitle(), optionList);
                }
            }
        }
        List<Map<String, Object>> listMapsTemp = new ArrayList<>();
        for (Map<String, Object> obj : listMaps) {
            Map<String, Object> objTemp = new HashMap<>();
            for (Map.Entry<String, Object> entry : obj.entrySet()) {
                String column = entry.getKey();
                String data = obj.get(column) == null ? "" : String.valueOf(obj.get(column));
                List<ProjectCollectInfoOption> optionList = optionMap.get(entry.getKey());
                if (CollUtil.isNotEmpty(optionList)) {
                    String[] dataStr = data.split(",");
                    if (dataStr != null && dataStr.length > 0) {
                        StringBuilder columnstr = new StringBuilder();
                        for (int m = 0; m < dataStr.length; m++) {
                            for (int j = 0; j < optionList.size(); j++) {
                                if (dataStr[m].equals(optionList.get(j).getOptionValue())) {
                                    columnstr.append(optionList.get(j).getOptionLabel() + ",");
                                    break;
                                }
                            }
                        }
                        if (StringUtils.isNotBlank(columnstr)) {
                            columnstr = columnstr.deleteCharAt(columnstr.length() - 1);
                        }
                        objTemp.put(column, columnstr.toString());
                    }
                }

                switch (column) {
                    case "studentId":
                        String studentSubjectNames = studentSubjectMap.get(data);
                        objTemp.put("报考科目", studentSubjectNames);
                        break;
                    case "createDate":
                        String createDate = DateUtil.getStringFormatTimeStamp(data);
                        objTemp.put("报考时间", createDate);
                        break;
                    case "性别":
                        if (data.equals("0")) {
                            objTemp.put(column, "男");
                        } else if (data.equals("1")) {
                            objTemp.put(column, "女");
                        } else {
                            objTemp.put(column, data);
                        }
                        break;
                    case "证件类型":
                        String desc = CertificateTypeEnum.getDescByType(data);
                        objTemp.put(column, desc);
                        break;
                    default:
                        if (StrUtil.isNotBlank(data)) {
                            if (data.equals("true")) {
                                objTemp.put(column, "是");
                                break;
                            } else if (data.equals("false")) {
                                objTemp.put(column, "否");
                                break;
                            }
                            if (null == objTemp.get(column)) {
                                objTemp.put(column, data);
                            }
                            break;
                        }
                }
            }
            listMapsTemp.add(objTemp);
        }


        for (int i = 0; i < listMapsTemp.size(); i++) {
            Map<String, Object> obj = listMapsTemp.get(i);
            List<String> tempdataOne = new ArrayList<>();
            for (String title : titleColumnList) {
                Object value = obj.get(title);
                if (ObjectUtil.isNotNull(value)) {
                    tempdataOne.add(String.valueOf(value));
                } else {
                    tempdataOne.add(StrUtil.EMPTY);
                }
            }
            dataResult.add(tempdataOne);
        }
        return dataResult;
    }


    public String exportStudentListV2(StudentInfoParam param) throws Exception {
        String projectId = param.getProjectId();

        // 构建导出表的名称
        String exportFileName = this.getExportFileName(param.getProjectId());
        log.info("# 11.1.7 管理端：导出考生列表exportFileName:{}", exportFileName);


        String titleColumn = getTitleColumn(projectId);
        log.info("# 11.1.7 管理端：导出考生列表titleColumn={}", titleColumn);
        String titleString = "subjectNames,createDate," + titleColumn;
        String[] titleColumns = titleString.split(",");


        String titleNameString = "报考科目,报名时间," + titleColumn;
        String[] titleName = titleNameString.split(","); // 表头，列名
        StringBuilder typeColums = new StringBuilder();
        typeColums.append("input,date,");

        // 采集信息有选项的数据集合
        Map<String, List<ProjectCollectInfoOption>> optionMap = new HashMap<>();
        Map<String, List<ProjectCollectInfoOption>> optionMapTemp = iProjectCollectInfoOptionService.getOptionListMap(param.getProjectId());
        List<ProjectCollectInfo> list = iProjectCollectInfoService.getProjectCollectInfosByPid(param.getProjectId());
        for (ProjectCollectInfo projectCollectInfo : list) {
            typeColums.append(projectCollectInfo.getComponentType());
            typeColums.append(",");
            if (ComponentTypeEnum.componentTypeHasOption(projectCollectInfo.getComponentType())) {
                List<ProjectCollectInfoOption> optionList = optionMapTemp.get(projectCollectInfo.getId());
                if (CollectionUtils.isNotEmpty(optionList)) {
                    optionMap.put(projectCollectInfo.getTitle(), optionList);
                }
            }
        }
        ProgressManager.updateProgressCurrent(20L, null);
        log.info("## 导出学生完成 %{}", 20L);
        if (StringUtils.isNotBlank(typeColums)) {
            typeColums = typeColums.deleteCharAt(typeColums.length() - 1);
        }
        int[] array = new int[titleColumns.length];
        for (int i = 0; i < array.length; i++) {
            array[i] = TITLE_SIZE;
        }

        // 动态生成列SQL
        String columns = getExportColumns(projectId);
        ProgressManager.updateProgressCurrent(40L, null);
        log.info("## 导出学生完成 %{}", 40L);
        List<String> studentIds = new ArrayList<String>();
        // 查询考生信息列表
        if (StringUtils.isNotEmpty(param.getStudentIds())) {
            for (int i = 0; i < param.getStudentIds().split(",").length; i++) {
                studentIds.add(param.getStudentIds().split(",")[i]);
            }
        }
        param.setColumns(columns);
        param.setIds(studentIds);
        param.setSize(-1);
        List<Map<String, Object>> listMaps = projectSubjectMapper.getAllList(param);
        ProgressManager.updateProgressCurrent(60L, null);
        log.info("## 导出学生完成 %{}", 60L);
        for (int i = 0; i < listMaps.size(); i++) {
            Map<String, Object> obj = listMaps.get(i);
            for (Map.Entry<String, Object> entry : obj.entrySet()) {
                if (entry.getKey().equals(ComponentNameEnum.office.getDesc()) && entry.getValue().toString().contains("[")) {
                    JSONArray arr = JSONArray.parseArray(entry.getValue().toString());
                    String str = "";
                    for (int j = 0; j < arr.size(); j++) {
                        str = str + "," + arr.getString(j);
                    }
                    entry.setValue(str.substring(1));
                }
            }
            for (int columnIndex = 0; columnIndex < titleName.length; columnIndex++) {
                String column = titleName[columnIndex].trim();
                List<ProjectCollectInfoOption> optionList = optionMap.get(column);
                if (CollUtil.isNotEmpty(optionList)) {
                    if (StringUtils.isNotBlank(columns)) {
                        String data = obj.get(column) == null ? "" : obj.get(column).toString();
                        String[] dataStr = data.split(",");
                        if (dataStr != null && dataStr.length > 0) {
                            StringBuilder columnstr = new StringBuilder();
                            for (int m = 0; m < dataStr.length; m++) {
                                for (int j = 0; j < optionList.size(); j++) {
                                    if (dataStr[m].equals(optionList.get(j).getOptionValue())) {
                                        columnstr.append(optionList.get(j).getOptionLabel() + ",");
                                        break;
                                    }
                                }
                            }
                            if (StringUtils.isNotBlank(columnstr)) {
                                columnstr = columnstr.deleteCharAt(columnstr.length() - 1);
                            }
                            obj.put(column, columnstr.toString());
                        }
                    }
                }
            }
        }
        ProgressManager.updateProgressCurrent(80L, null);
        log.info("## 导出学生完成 %{}", 80L);
        String urlLink = configManager.getBmlistExportUrlLinkInfo();
        String zipUrl = uploadFileToHuaweiUtil.zipMapExcelUploadToHuaWei(exportFileName + ".zip", titleColumns, titleName, typeColums.toString().split(","), array, listMaps, Boolean.valueOf(urlLink));
        log.info("exportStudentList: zipUrl：{}", zipUrl);
        ProgressManager.updateProgressCurrent(100L, zipUrl);
        log.info("## 导出学生完成 %{}", 100L);
        return zipUrl;
    }

    /**
     * @Params:
     * @Description: 导出上传华为云
     * @Author: STARF
     * @CreateDate: 2022/6/1 16:26
     **/
    @Override
    public String downLoadStudentList(StudentInfoParam param) {
        String projectId = param.getProjectId();
        if (StringUtils.isEmpty(projectId)) {
            throw new InvalidRequestException(Constant.RESPONSE_CODE_31111001, "项目id不能为空");
        }
        Project project = projectMapper.selectById(projectId);
        if (null == project) {
            throw new InvalidRequestException(Constant.RESPONSE_CODE_31111001, "项目不存在");
        }
        // 如果没有机构采集信息则不设置机构权限查询
        Boolean hasOfficePermission = iProjectCollectInfoService.isComponentRequired(param.getProjectId(), ComponentNameEnum.office.getCode());
        if (!hasOfficePermission) {
            param.setDeptIds(null);
        }
        ProjectDataDownLoadRecord projectDataDownLoadRecord = new ProjectDataDownLoadRecord();
        projectDataDownLoadRecord.setId(UUIDUtils.newSortUUID());
        projectDataDownLoadRecord.setProjectId(projectId);
        projectDataDownLoadRecord.setOfficeId(param.getOfficeId());
        projectDataDownLoadRecord.setDeptId(param.getDeptId());
        projectDataDownLoadRecord.setPermissions(CollUtil.isNotEmpty(param.getDeptIds()) ? MD5Util.encode(FastJsonUtil.getBeanToJson(param)) : null);
        projectDataDownLoadRecord.setDlParam(param.toString());
        projectDataDownLoadRecord.setFileType(ProjectDownLoadFileTypeEnum.project_student_zip.getType());
        projectDataDownLoadRecord.setStatus(ProjectDownLoadStatusEnum.downloading.getStatus());
        projectDataDownLoadRecord.setRemark(ProjectDownLoadFileTypeEnum.project_student_zip.getDesc());
        iProjectDataDownLoadRecordService.save(projectDataDownLoadRecord);

        String zipUrl = this.exportStudentList(param);
        if (StringUtils.isEmpty(zipUrl)) {
            // 更新文件下载记录
            projectDataDownLoadRecord.setStatus(ProjectDownLoadStatusEnum.fail.getStatus());
            projectDataDownLoadRecord.setFileUrl(zipUrl);
            iProjectDataDownLoadRecordService.updateById(projectDataDownLoadRecord);
        } else {
            // 更新文件下载记录
            projectDataDownLoadRecord.setStatus(ProjectDownLoadStatusEnum.finish.getStatus());
            projectDataDownLoadRecord.setFileUrl(zipUrl);
            iProjectDataDownLoadRecordService.updateById(projectDataDownLoadRecord);
        }
        return zipUrl;
    }

    /**
     * @Params:
     * @Description:
     * @Author: STARF
     * @CreateDate: 2022/6/2 14:29
     **/
    public boolean isLastTime(String projectId, LocalDateTime time) {
        QueryWrapper<StudentProject> spWrapper = new QueryWrapper<>();
        spWrapper.lambda().eq(StudentProject::getProjectId, projectId)
                .eq(StudentProject::getDelFlag, false)
                .orderByDesc(StudentProject::getUpdateDate).last("limit 1");
        StudentProject studentProject = studentProjectMapper.selectOne(spWrapper);
        if (time.isBefore(studentProject.getUpdateDate())) {
            return false;
        }

        QueryWrapper<StudentSubject> ssWrapper = new QueryWrapper<>();
        ssWrapper.lambda().eq(StudentSubject::getProjectId, projectId)
                .eq(StudentSubject::getDelFlag, false)
                .orderByDesc(StudentSubject::getUpdateDate).last("limit 1");
        StudentSubject studentSubject = studentSubjectMapper.selectOne(ssWrapper);
        if (null != studentSubject && time.isBefore(studentSubject.getUpdateDate())) {
            return false;
        }

        QueryWrapper<StudentInfo> siWrapper = new QueryWrapper<>();
        siWrapper.lambda().eq(StudentInfo::getProjectId, projectId)
                .orderByDesc(StudentInfo::getUpdateDate).last("limit 1");
        StudentInfo studentInfo = studentInfoMapper.selectOne(siWrapper);
        if (null != studentInfo && time.isBefore(studentInfo.getUpdateDate())) {
            return false;
        }

        return true;
    }

    /**
     * 生成excel的名称，由于excel里面的sheet也使用这个名称，而sheet中不允许名称存在《:》等特殊字符
     *
     * @param projectId
     * @return
     */
    private String getExportFileName(String projectId) {
        Project project = projectMapper.selectById(projectId);
        String dateString = DateUtil.getTimeAll();
        String title = dateString + "-" + project.getProjectName() + "-考生详情";
        return StrUtil.replace(title, ":", "_");
    }

    @Override
    public List<StudentProjectVo> queryStudentProject(String regId) {
        List<StudentProjectVo> list = new ArrayList<StudentProjectVo>();
        try {
            list = projectMapper.queryStuProject(regId);
        } catch (Exception ex) {
            ex.printStackTrace();
            throw ex;
        }
        return list;
    }

    /**
     * 判断照片是否合格
     */
    @Override
    public String uploadFile(MultipartFile multipartFile, String projectCollectInfoId) {
        QueryWrapper<ProjectImageStandard> wrapper = new QueryWrapper<ProjectImageStandard>();
        wrapper.eq("project_collect_info_id", projectCollectInfoId);
        ProjectImageStandard projectImageStandard = iProjectImageStandardService.getOne(wrapper);

        // MultipartFile multipartFile = multipartFile; 获取请求传过来的MultipartFile
        String fileName = multipartFile.getOriginalFilename();
        String prefix = "";
        if (StringUtils.isNotBlank(fileName)) {
            prefix = fileName.substring(fileName.lastIndexOf("."));
        }
        try {
            long size = multipartFile.getSize();
            double fileSize = (double) size / (1024.00 * 1024); // M
            if (fileSize > Double.valueOf(projectImageStandard.getMaxSize())
                    || fileSize < Double.valueOf(projectImageStandard.getMinSize())) { // 判断图片大小
                // 单位m
                return "图片尺寸不合适.范围:" + projectImageStandard.getMinSize() + "- " + projectImageStandard.getMaxSize();
            }
            File file = File.createTempFile(prefix, String.valueOf(System.currentTimeMillis())); // 创建临时文件
            BmFileUtils.copyInputStreamToFile(multipartFile.getInputStream(), file);
            BufferedImage bufferedImage = ImageIO.read(file); // 通过临时文件获取图片流
            if (bufferedImage == null) {
                // 证明上传的文件不是图片，获取图片流失败，不进行下面的操作
                return "上传的文件不是图片,请重新上传！";
            }
            Integer width = bufferedImage.getWidth(); // 通过图片流获取图片宽度
            if (projectImageStandard.getMinWidth() > width || width > projectImageStandard.getMaxWidth()) {
                return "照片宽度过大或过小，请重新上传！";
            }
            Integer height = bufferedImage.getHeight(); // 通过图片流获取图片高度
            if (projectImageStandard.getMinHeight() > height || height > projectImageStandard.getMaxHeight()) {
                return "照片高度过大或过小，请重新上传！";
            }
            // 省略逻辑判断
        } catch (Exception e) {
            // 省略异常操作
        }

        return "";
    }

    @Override
    public IPage<StudentInfoDeatailVo> getPageStudent(PageParam<StudentInfoDeatailVo> pageParam, String enrollId,
                                                      String subjectId, String queryStr, String auditState, String payState) {
        return studentInfoMapper.getPageStudent(pageParam, enrollId, subjectId, queryStr, auditState, payState);
    }

    @Override
    public List<StudentSubjectDetailVo> getProjectSubjectByStuId(String projectId, String studentId) {
        return projectSubjectMapper.getProjectSubjectByStuId(projectId, studentId);
    }

    /**
     * 判断手机+邮箱是否重复
     */
    @Override
    public void isAgainData(StudentInfoListVo studentInfoListVo) {
        // 如果不是集体报名校验需要的参数
        if (!studentInfoListVo.getGroupRegist()) {
            if (StrUtil.isBlank(studentInfoListVo.getRegId())) {
                BusinessLogicException.throwException(31081109, "考生账号不能为空");
            }
        }

        Project project = iProjectService.getById(studentInfoListVo.getProjectId());
        if (project.getEndTime() != null) {
            // 将当前时间转为时间戳
            if (project.getEndTime().isBefore(LocalDateTime.now())) {
                BusinessLogicException.throwException(Constant.RESPONSE_CODE_31010163, "报名时间已经截止！");
            }
            if (project.getBeginTime().isAfter(LocalDateTime.now())) {
                BusinessLogicException.throwException(Constant.RESPONSE_CODE_31010164, "未到报名时间！");
            }
        }
        // 分别获取项目收集项id
        String nameId = projectMapper.getCollectIdByProject(ComponentNameEnum.name.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String phoneCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.phone.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String emailCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.email.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String idCardTypeId = projectMapper.getCollectIdByProject(ComponentNameEnum.certificatetype.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String idCardCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.idcard.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String birthdayCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.birthday.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String admissionnoId = projectMapper.getCollectIdByProject(ComponentNameEnum.admissionno.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String idcardphotoId = projectMapper.getCollectIdByProject(ComponentNameEnum.idcardphoto.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());

        // 附件id
        String enclosureId = projectMapper.getCollectIdByProject("附件", studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());

        // 是不是必选的
        String enclosureIdIsrequre = projectMapper.getCollectRequiredByProject("附件", studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());


        QueryWrapper<ProjectCollectInfo> wrapper = new QueryWrapper<ProjectCollectInfo>();
        wrapper.eq("component_name", "图片");
        wrapper.eq("project_id", studentInfoListVo.getProjectId());
        List<ProjectCollectInfo> imagelist = iProjectCollectInfoService.list(wrapper);


        String nameStr = "";
        String birthdayStr = "";
        String idcardStr = "";
        String idCardTypeStr = "";

        List<StudentInfo> list = studentInfoListVo.getList();
        boolean hasphone = true;
        boolean hasemail = true;
        boolean phoneRepeat = false;
        boolean emailRepeat = false;
        boolean idCard = false;


        boolean idCardFlag = false;
        boolean birthday = false;
        boolean enclosure = false;
        boolean admissionnoFlag = false;
        boolean admissionnoRuleFlag = false;
        boolean photoIdFlag = false;
        boolean idcardphotoIdFlag = false;

        for (StudentInfo studentInfo : list) {
            if (StringUtils.isNotBlank(idCardTypeId)) {
                if (idCardTypeId.equals(studentInfo.getProjectCollectInfoId())) {
                    idCardTypeStr = studentInfo.getValue();
                }
            }
            if (StringUtils.isNotBlank(nameId)) {
                if (nameId.equals(studentInfo.getProjectCollectInfoId())) {
                    nameStr = studentInfo.getValue();
                }
            }
        }

        for (StudentInfo studentInfo : list) {
            // 附件
            if (StringUtils.isNotBlank(enclosureId)) {
                if (enclosureId.equals(studentInfo.getProjectCollectInfoId())) {
                    if (StringUtils.isEmpty(studentInfo.getValue()) && BmProjectCcollectInfoRequiredEnum.REQUIRED.getRequiredStatus().equals(enclosureIdIsrequre)) {
                        enclosure = true;
                        break;
                    }
                }
            }
            // 图片
            if (imagelist != null && imagelist.size() > 0) {
                for (int j = 0; j < imagelist.size(); j++) {
                    String photoId = imagelist.get(j).getId();
                    String isRequired = String.valueOf(imagelist.get(j).getRequired());// 是否必填
                    Integer minUploadNum = projectMapper.getCollectUploadNumByProject(photoId);// 最少上传数量：cj_project_image_standard
                    if (StringUtils.isNotBlank(photoId)) {
                        if (photoId.equals(studentInfo.getProjectCollectInfoId())) {
                            // 必填
                            if (BmProjectCcollectInfoRequiredEnum.REQUIRED.getRequiredStatus().equals(isRequired)) {
                                if (StringUtils.isEmpty(studentInfo.getValue())) {
                                    photoIdFlag = true;
                                    break;
                                }
                                int num = 0;
                                String[] strings = studentInfo.getValue().split(",");
                                for (String string : strings) {
                                    if (StringUtils.isNotBlank(string)) {
                                        num++;
                                    }
                                }
                                if (num < minUploadNum) {
                                    photoIdFlag = true;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            // 身份证照片
            if (StringUtils.isNotBlank(idcardphotoId)) {
                if (idcardphotoId.equals(studentInfo.getProjectCollectInfoId())) {
                    if (StringUtils.isEmpty(studentInfo.getValue())) {
                        String idcardphotoIsrequre = projectMapper.getCollectRequiredByProject("idcardphoto", studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
                        if (BmProjectCcollectInfoRequiredEnum.REQUIRED.getRequiredStatus().equals(idcardphotoIsrequre)) {
                            idcardphotoIdFlag = true;
                            break;
                        }
                    }
                }
            }

            // 有电话号码采集信息
            if (StringUtils.isNotBlank(phoneCollectId)) {
                if (phoneCollectId.equals(studentInfo.getProjectCollectInfoId())) {
                    String phoneCollectIdIsrequre = projectMapper.getCollectRequiredByProject(ComponentNameEnum.phone.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
                    // 如果电话号码是必填的
                    if (BmProjectCcollectInfoRequiredEnum.REQUIRED.getRequiredStatus().equals(phoneCollectIdIsrequre)) {
                        if (StringUtils.isBlank(studentInfo.getValue())) {
                            hasphone = false;
                        }
                    }
                    if (StringUtils.isNotBlank(studentInfo.getValue())) {
                        StudentInfo objInfo = studentInfoMapper.getStuByCollectId(phoneCollectId, studentInfoListVo.getProjectId(), studentInfo.getValue());
                        if (objInfo != null) {
                            phoneRepeat = true;
                            // 手机有重复
                            continue;
                        }
                    }
                }
            }

            // 有邮箱采集信息
            if (StringUtils.isNotBlank(emailCollectId)) {
                if (emailCollectId.equals(studentInfo.getProjectCollectInfoId())) {
                    String emailCollectIdIsrequre = projectMapper.getCollectRequiredByProject(ComponentNameEnum.email.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
                    if (BmProjectCcollectInfoRequiredEnum.REQUIRED.getRequiredStatus().equals(emailCollectIdIsrequre)) {
                        if (StringUtils.isBlank(studentInfo.getValue())) {
                            hasemail = false;
                        }
                    }
                    if (StringUtils.isNotBlank(studentInfo.getValue())) {
                        StudentInfo objInfo = studentInfoMapper.getStuByCollectId(emailCollectId, studentInfoListVo.getProjectId(), studentInfo.getValue());
                        if (objInfo != null) {
                            emailRepeat = true;
                            // email有重复
                            continue;
                        }
                    }
                }
            }

            if (StringUtils.isNotBlank(admissionnoId)) {
                if (admissionnoId.equals(studentInfo.getProjectCollectInfoId())) {
                    String admissionnoIdIsrequre = projectMapper.getCollectRequiredByProject(ComponentNameEnum.admissionno.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
                    if (BmProjectCcollectInfoRequiredEnum.REQUIRED.getRequiredStatus().equals(admissionnoIdIsrequre)) {
                        try {
                            CheckUtil.check(studentInfo.getValue(), "准考证号", StrRuler.admissionNo());
                        } catch (CheckException e) {
                            admissionnoRuleFlag = true;
                            // 准考证号码重复
                            continue;
                        }
                    }
                    if (StringUtils.isNotBlank(studentInfo.getValue())) {
                        StudentInfo objInfo = studentInfoMapper.getStuByCollectId(admissionnoId, studentInfoListVo.getProjectId(), studentInfo.getValue());
                        if (objInfo != null) {
                            admissionnoFlag = true;
                            // 准考证号码重复
                            continue;
                        }
                    }
                }
            }

            if (StringUtils.isNotBlank(idCardCollectId)) {
                if (idCardCollectId.equals(studentInfo.getProjectCollectInfoId())) {
                    StudentInfo objInfo = studentInfoMapper.getStuByCollectId(idCardCollectId, studentInfoListVo.getProjectId(), studentInfo.getValue());
                    if (objInfo != null) {
                        idCardFlag = true;
                        // 证件号码有重复
                        continue;
                    }
                    // 判断是否非开放性报名
                    if (0 == project.getIsOpen()) {
                        NonOpenInfo nonOpenInfo = nonOpenMapper.queryStudentByCardNum(studentInfoListVo.getProjectId(), studentInfo.getValue());
                        if (nonOpenInfo == null) {
                            InvalidRequestException.throwException(31010159, "抱歉，您暂时没有报名资格！");
                        } else {
                            if (!nameStr.equals(nonOpenInfo.getStudentName()) || !studentInfo.getValue().equals(nonOpenInfo.getCardNumber())) {
                                InvalidRequestException.throwException(31010160, "姓名与报名资格导入姓名不符！");
                            }
                        }
                    }
                    // 如果是身份证
                    if (StringUtils.isNotBlank(idCardTypeStr) && CertificateTypeEnum.IDCARD.getType().equals(idCardTypeStr)) {
                        String tipInfo = IDCardUtil.IdCardValidate(studentInfo.getValue());
                        idcardStr = studentInfo.getValue();
                        if (!"YES".equals(tipInfo)) {
                            idCard = true;
                            // 身份证不合法
                            continue;
                        }
                    } else if (StringUtils.isNotBlank(idCardTypeStr) && CertificateTypeEnum.HONGKONGMACAOANDTAIWANIDCARD.getType().equals(idCardTypeStr)) {
                        if (!idCardTypeStr.matches(Constant.HKMACAOTAWAN)) {
                            idCard = true;
                            continue;
                        }
                    }

                }
            }
            if (CertificateTypeEnum.IDCARD.getType().equals(idCardTypeStr)) {
                if (StringUtils.isNotBlank(birthdayCollectId)) {
                    if (birthdayCollectId.equals(studentInfo.getProjectCollectInfoId())) {
                        // 出生日期
                        if (StringUtils.isNotBlank(studentInfo.getValue())) {
                            String cs = studentInfo.getValue() + " 00:00:00";
                            DateFormat format1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                            Date csTime = null;
                            try {
                                csTime = format1.parse(cs);
                            } catch (ParseException e) {
                                e.printStackTrace();
                            }
                            birthdayStr = DateUtil.dateToStrF(csTime);
                            Date currentTime = new Date();
                            if (csTime != null && currentTime != null) {
                                if (csTime.getTime() > currentTime.getTime()) {
                                    birthday = true;
                                    // 出生日期大于当前时间
                                    continue;
                                }
                            }
                        }
                    }
                }
            }

        }

        if (!StringUtils.isBlank(idcardStr) && !StringUtils.isBlank(birthdayStr)) {
            if (idcardStr.length() > 14) {
                String tempstr = idcardStr.substring(6, 14);
                if (!tempstr.equals(birthdayStr.replaceAll("-", ""))) {
                    InvalidRequestException.throwException(31010155, "输入的出生日期和证件号码不一致，请重新输入");
                }
            }
        }
        // 手机+邮箱 重复
        if (emailRepeat && phoneRepeat) {
            InvalidRequestException.throwException(31010153, "手机号、邮箱已存在，请重新输入");
        }
        if (admissionnoFlag) {
            InvalidRequestException.throwException(31011153, "准考证号存在，请重新输入");
        }
        if (admissionnoRuleFlag) {
            InvalidRequestException.throwException(31011154, "准考证号不符合规范，请重新输入");
        }
        // 身份证不合法
        if (idCard) {
            InvalidRequestException.throwException(31010118, "身份证不合法");
        }
        if (idCardFlag) {
            InvalidRequestException.throwException(31010119, "身份证号码已存在");
        }
        // 出生日期大于当前时间
        if (birthday) {
            InvalidRequestException.throwException(31010154, "出生日期不能是当前时间之后，请重新输入");
        }
        if (enclosure) {
            InvalidRequestException.throwException(31010156, "请选择附件");
        }
        // 照片为空
        if (photoIdFlag) {
            InvalidRequestException.throwException(31010157, "照片为空");
        }
        // 身份证照片为空
        if (idcardphotoIdFlag) {
            InvalidRequestException.throwException(31010158, "身份证照片为空");
        }
        if (!hasphone) {
            InvalidRequestException.throwException(31081106, "电话号码不能为空！请输入");
        }
        if (!hasemail) {
            InvalidRequestException.throwException(31081107, "邮箱不能为空！请输入！");
        }

        // 校验必填数据的完整性
        this.validateRequiredData(studentInfoListVo.getProjectId(), studentInfoListVo.getList());
    }

    /**
     * 校验必填数据的完整性
     * @param projectId
     * @param studentInfoList
     */
    private void validateRequiredData(String projectId, List<StudentInfo> studentInfoList) {
        List<ProjectCollectInfo> projectCollectInfos = iProjectCollectInfoService.getProjectCollectInfosByPid(projectId);
        Map<String, ProjectCollectInfo> projectCollectInfoIdMappingData = projectCollectInfos.stream()
                .collect(Collectors.toMap(ProjectCollectInfo::getId, Function.identity()));

        for (StudentInfo studentInfo : studentInfoList) {
            String projectCollectInfoId = studentInfo.getProjectCollectInfoId();
            if (StrUtil.isBlank(projectCollectInfoId)) {
                BusinessLogicException.throwException(31081114, "缺少上传的采集信息", studentInfo);
            }

            ProjectCollectInfo projectCollectInfo = projectCollectInfoIdMappingData.get(projectCollectInfoId);
            if (projectCollectInfo != null) {
                if (projectCollectInfo.getRequired() == CommonConstant.ONE) {
                    if (StrUtil.isBlank(studentInfo.getValue())) {
                        BusinessLogicException.throwException(31081115, "必填项的采集数据未上传", studentInfo);
                    }
                }
            }
        }
    }


    /**
     * 判断手机+邮箱是否重复
     */
    @Override
    public void checkData(StudentInfoListVo studentInfoListVo) {
        // 获取报名性项目
        Project project = iProjectService.getById(studentInfoListVo.getProjectId());
        // 获取当前报名考生的项目下报名的收集信息
        List<StudentInfoVo> infoList = getByStudentId(studentInfoListVo.getProjectId(), studentInfoListVo.getStudentId());
        // 分别获取项目收集项id
        String nameId = projectMapper.getCollectIdByProject(ComponentNameEnum.name.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String phoneCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.phone.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String emailCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.email.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String idCardTypeId = projectMapper.getCollectIdByProject(ComponentNameEnum.certificatetype.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String idCardCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.idcard.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String birthdayCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.birthday.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String admissionnoId = projectMapper.getCollectIdByProject(ComponentNameEnum.admissionno.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());

        String enclosureId = projectMapper.getCollectIdByProject("附件", studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String enclosureIdIsrequre = projectMapper.getCollectRequiredByProject("附件", studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());// 是否必填

        QueryWrapper<ProjectCollectInfo> wrapper = new QueryWrapper<ProjectCollectInfo>();
        wrapper.eq("component_name", "图片");
        wrapper.eq("project_id", studentInfoListVo.getProjectId());
        List<ProjectCollectInfo> imagelist = iProjectCollectInfoService.list(wrapper);

        String idcardphotoId = projectMapper.getCollectIdByProject("idcardphoto", studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        // 名称
        String nameStr = "";
        // 出生日期
        String birthdayStr = "";
        // 电话号码
        String phoneStr = "";
        // 身份证号码
        String idcardStr = "";
        // 邮箱
        String emailStr = "";
        // 证件类型
        String idCardTypeStr = "";
        // 准考证号码
        String admissionnoStr = "";


        // 老的姓名
        String oldNameStr = "";
        // 老的电话号码
        String oldPhoneStr = "";
        // 老的邮箱
        String oldEmailStr = "";
        // 老的证件类型
        String oldIdCardTypeStr = "";
        // 老的证件号码
        String oldIdcardStr = "";
        // 老的准考证号码
        String oldAdmissionnoStr = "";

        // 获取从前端传的考生信息收集
        List<StudentInfo> list = studentInfoListVo.getList();

        boolean phone = false;
        boolean email = false;
        // 证件是不是合法
        boolean idCard = false;
        // 判断身份证是不是存在
        boolean idCardFlag = false;
        boolean birthday = false;
        boolean enclosure = false;
        boolean photoIdFlag = false;
        boolean idcardphotoIdFlag = false;
        boolean admissionnoFlag = false;
        boolean admissionnoRuleFlag = false;


        for (StudentInfo studentInfo : list) {
            if (StringUtils.isNotBlank(idCardTypeId)) {
                if (idCardTypeId.equals(studentInfo.getProjectCollectInfoId())) {
                    idCardTypeStr = studentInfo.getValue();
                }
            }
            if (StringUtils.isNotBlank(idCardCollectId)) {
                if (idCardCollectId.equals(studentInfo.getProjectCollectInfoId())) {
                    idcardStr = studentInfo.getValue();
                }
            }
            if (StringUtils.isNotBlank(phoneCollectId)) {
                if (phoneCollectId.equals(studentInfo.getProjectCollectInfoId())) {
                    phoneStr = studentInfo.getValue();
                }
            }
            if (StringUtils.isNotBlank(emailCollectId)) {
                if (emailCollectId.equals(studentInfo.getProjectCollectInfoId())) {
                    emailStr = studentInfo.getValue();
                }
            }
            if (nameId.equals(studentInfo.getProjectCollectInfoId())) {
                nameStr = studentInfo.getValue();
            }
            if (StringUtils.isNotBlank(birthdayCollectId)) {
                if (birthdayCollectId.equals(studentInfo.getProjectCollectInfoId())) {
                    birthdayStr = studentInfo.getValue();
                }
            }
            if (StringUtils.isNotBlank(admissionnoId)) {
                if (admissionnoId.equals(studentInfo.getProjectCollectInfoId())) {
                    admissionnoStr = studentInfo.getValue();
                }
            }

        }

        for (StudentInfoVo studentInfo : infoList) {
            if (StringUtils.isNotBlank(idCardTypeId)) {
                if (idCardTypeId.equals(studentInfo.getProjectCollectInfoId())) {
                    oldIdCardTypeStr = studentInfo.getValue();
                }
            }

            if (StringUtils.isNotBlank(idCardCollectId)) {
                if (idCardCollectId.equals(studentInfo.getProjectCollectInfoId())) {
                    oldIdcardStr = studentInfo.getValue();
                }
            }
            if (StringUtils.isNotBlank(phoneCollectId)) {
                if (phoneCollectId.equals(studentInfo.getProjectCollectInfoId())) {
                    oldPhoneStr = studentInfo.getValue();
                }
            }
            if (StringUtils.isNotBlank(emailCollectId)) {
                if (emailCollectId.equals(studentInfo.getProjectCollectInfoId())) {
                    oldEmailStr = studentInfo.getValue();
                }
            }
            if (StringUtils.isNotBlank(nameId)) {
                if (nameId.equals(studentInfo.getProjectCollectInfoId())) {
                    oldNameStr = studentInfo.getValue();
                }
            }

            if (StringUtils.isNotBlank(admissionnoId)) {
                if (admissionnoId.equals(studentInfo.getProjectCollectInfoId())) {
                    oldAdmissionnoStr = studentInfo.getValue();
                }
            }
        }

        // 如果修改的时候修改了身份证号码
        if (StringUtils.isNotBlank(idcardStr) && !idcardStr.equals(oldIdcardStr)) {
            // 查询身份证是不是存在
            StudentInfo newStudentInfo = studentInfoMapper.getStuByCollectId(idCardCollectId, studentInfoListVo.getProjectId(), idcardStr);
            if (newStudentInfo != null) {
                idCardFlag = true;
            } else {
                // 如果是非开放性考试项目
                if (ProjectOpenEnum.UNOPEN.getOpenStatus().equals(project.getIsOpen())) {
                    // 查询报名资格表，新考生是否有报名资格【以证件号码为标准】
                    NonOpenInfo nonOpenInfo = nonOpenMapper.queryStudentByCardNum(studentInfoListVo.getProjectId(), idcardStr);
                    if (nonOpenInfo == null) {
                        BusinessLogicException.throwException(Constant.RESPONSE_CODE_31010159, "抱歉，您暂时没有报名资格");
                    } else {
                        // 如果是有资格报考，比对身份证和名称是不是符合要求
                        if (StringUtils.isNotBlank(nameStr) && !nameStr.equals(nonOpenInfo.getStudentName())) {
                            BusinessLogicException.throwException(Constant.RESPONSE_CODE_31010160, "姓名与报名资格导入姓名不符！");
                        }
                    }
                }
            }
            if (StringUtils.isNotBlank(idCardTypeStr) && CertificateTypeEnum.IDCARD.getType().equals(idCardTypeStr)) {
                // 校验身份证是否在有效期
                String tipInfo = IDCardUtil.IdCardValidate(idcardStr);
                if (!"YES".equals(tipInfo)) {
                    idCard = true;
                }
            } else if (StringUtils.isNotBlank(idCardTypeStr) && CertificateTypeEnum.HONGKONGMACAOANDTAIWANIDCARD.getType().equals(idCardTypeStr)) {
                if (!idCardTypeStr.matches(Constant.HKMACAOTAWAN)) {
                    idCard = true;
                }
            } else if (StringUtils.isBlank(idCardTypeStr) && CertificateTypeEnum.IDCARD.getType().equals(oldIdCardTypeStr)) {
                String tipInfo = IDCardUtil.IdCardValidate(idcardStr);
                if (!"YES".equals(tipInfo)) {
                    idCard = true;
                }
            } else if (StringUtils.isBlank(idCardTypeStr) && CertificateTypeEnum.HONGKONGMACAOANDTAIWANIDCARD.getType().equals(oldIdCardTypeStr)) {
                if (!idCardTypeStr.matches(Constant.HKMACAOTAWAN)) {
                    idCard = true;
                }
            }
        }

        // 如果修改的时候，修改了姓名【名称不一致】
        if (StringUtils.isNotBlank(nameStr) && !nameStr.equals(oldNameStr)) {
            // 如果是非开放性报名
            if (ProjectOpenEnum.UNOPEN.getOpenStatus().equals(project.getIsOpen())) {
                if (StringUtils.isNotBlank(oldIdcardStr)) {
                    NonOpenInfo nonOpenInfo = nonOpenMapper.queryStudentByCardNum(studentInfoListVo.getProjectId(), oldIdcardStr);
                    if (nonOpenInfo == null) {
                        BusinessLogicException.throwException(Constant.RESPONSE_CODE_31010159, "抱歉，您暂时没有报名资格");
                    } else {
                        if (StringUtils.isNotBlank(oldIdcardStr) && !nameStr.equals(nonOpenInfo.getStudentName())) {
                            BusinessLogicException.throwException(Constant.RESPONSE_CODE_31010160, "姓名与报名资格导入姓名不符！");
                        }
                    }
                }
            }
        }

        if (StringUtils.isNotBlank(phoneCollectId) && !phoneStr.equals(oldPhoneStr)) {
            StudentInfo objInfo = studentInfoMapper.getStuByCollectId(phoneCollectId, studentInfoListVo.getProjectId(), phoneStr);
            if (objInfo != null) {
                phone = true;
            }
        }

        if (StringUtils.isNotBlank(emailCollectId) && !emailStr.equals(oldEmailStr)) {
            StudentInfo objInfo = studentInfoMapper.getStuByCollectId(emailCollectId, studentInfoListVo.getProjectId(), emailStr);
            if (objInfo != null) {
                email = true;
            }
        }

        if (StringUtils.isNotBlank(admissionnoId) && !admissionnoStr.equals(oldAdmissionnoStr)) {
            StudentInfo objInfo = studentInfoMapper.getStuByCollectId(admissionnoId, studentInfoListVo.getProjectId(), admissionnoStr);
            if (objInfo != null) {
                admissionnoFlag = true;
            }
            try {
                CheckUtil.check(admissionnoStr, "准考证号", StrRuler.admissionNo());
            } catch (CheckException e) {
                admissionnoRuleFlag = true;
            }
        }


        if (StringUtils.isNotBlank(birthdayCollectId) && StringUtils.isNotBlank(birthdayStr)) {
            String cs = birthdayStr + " 00:00:00";
            DateFormat format1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date csTime = null;
            try {
                csTime = format1.parse(cs);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            birthdayStr = DateUtil.dateToStrF(csTime);
            Date currentTime = new Date();
            if (csTime != null && currentTime != null) {
                if (csTime.getTime() > currentTime.getTime()) {
                    birthday = true;
                }
            }
        }

        for (StudentInfo studentInfo : list) {
            // 附件
            if (StringUtils.isNotBlank(enclosureId)) {
                if (enclosureId.equals(studentInfo.getProjectCollectInfoId())) {
                    if (StringUtils.isEmpty(studentInfo.getValue()) && BmProjectCcollectInfoRequiredEnum.REQUIRED.getRequiredStatus().equals(enclosureIdIsrequre)) {
                        enclosure = true;
                        break;
                    }
                }
            }
            // 图片
            if (imagelist != null && imagelist.size() > 0) {
                for (int j = 0; j < imagelist.size(); j++) {

                    String photoId = imagelist.get(j).getId();
                    String isRequired = String.valueOf(imagelist.get(j).getRequired());// 是否必填
                    Integer minUploadNum = projectMapper.getCollectUploadNumByProject(photoId);// 最少上传数量：cj_project_image_standard

                    if (StringUtils.isNotBlank(photoId)) {
                        if (photoId.equals(studentInfo.getProjectCollectInfoId())) {
                            // 必填
                            if ("1".equals(isRequired)) {
                                if (StringUtils.isEmpty(studentInfo.getValue())) {
                                    photoIdFlag = true;
                                    break;
                                }
                                int num = 0;
                                String[] strings = studentInfo.getValue().split(",");
                                for (String string : strings) {
                                    if (StringUtils.isNotBlank(string)) {
                                        num++;
                                    }
                                }
                                if (num < minUploadNum) {
                                    photoIdFlag = true;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            // 身份证照片
            if (StringUtils.isNotBlank(idcardphotoId)) {
                if (idcardphotoId.equals(studentInfo.getProjectCollectInfoId())) {
                    if (StringUtils.isEmpty(studentInfo.getValue())) {
                        idcardphotoIdFlag = true;
                        break;
                    }
                }
            }
        }

        if (!StringUtils.isBlank(idcardStr) && !StringUtils.isBlank(birthdayStr)) {
            if (idcardStr.length() > 14) {
                String tempstr = idcardStr.substring(6, 14);
                if (!tempstr.equals(birthdayStr.replaceAll("-", ""))) {
                    BusinessLogicException.throwException(Constant.RESPONSE_CODE_31010155, "出生日期与身份证不符，请重新输入！");
                }
            }
        } else if (!StringUtils.isBlank(oldIdcardStr) && !StringUtils.isBlank(birthdayStr)) {
            if (oldIdcardStr.length() > 14) {
                String tempstr = oldIdcardStr.substring(6, 14);
                if (!tempstr.equals(birthdayStr.replaceAll("-", ""))) {
                    BusinessLogicException.throwException(Constant.RESPONSE_CODE_31010155, "出生日期与身份证不符，请重新输入！");
                }
            }
        }
        // 手机+邮箱 重复
        if (email && phone) {
            BusinessLogicException.throwException(Constant.RESPONSE_CODE_31010153, "手机号、邮箱已存在，请重新输入！");
        }
        // 准考证处重复
        if (admissionnoFlag) {
            BusinessLogicException.throwException(Constant.RESPONSE_CODE_31011153, "准考证已存在，请重新输入！");
        }
        if (admissionnoRuleFlag) {
            BusinessLogicException.throwException(Constant.RESPONSE_CODE_31011154, "准考证号不符合规范，请重新输入！");
        }
        // 身份证不合法
        if (idCard) {
            BusinessLogicException.throwException(Constant.RESPONSE_CODE_31010118, "身份证不合法，请重新输入！");
        }
        if (idCardFlag) {
            BusinessLogicException.throwException(Constant.RESPONSE_CODE_31010119, "身份证已存在，请重新输入！");
        }
        // 出生日期大于当前时间
        if (birthday) {
            BusinessLogicException.throwException(Constant.RESPONSE_CODE_31010154, "出生日期不能是当前时间之后，请重新输入！");
        }
        if (enclosure) {
            BusinessLogicException.throwException(Constant.RESPONSE_CODE_31010156, "请选择附件！！");
        }
        // 照片为空
        if (photoIdFlag) {
            BusinessLogicException.throwException(31081206, "照片不能为空");
        }
        // 身份证照片为空
        if (idcardphotoIdFlag) {
            BusinessLogicException.throwException(31081207, "身份证照片不能为空");
        }

        // 校验必填数据的完整性
        this.validateRequiredData(studentInfoListVo.getProjectId(), studentInfoListVo.getList());
    }

    /**
     * 判断手机+邮箱是否重复
     */
    @Override
    public void batchImportManualDataCheck(BatchImportManualParam studentInfoListVo) {
        Project project = iProjectService.getById(studentInfoListVo.getProjectId());
        if (project.getEndTime() != null) {
            // 将当前时间转为时间戳
            if (project.getEndTime().isBefore(LocalDateTime.now())) {
                BusinessLogicException.throwException(Constant.RESPONSE_CODE_31010163, "报名时间已经截止！");
            }
            if (project.getBeginTime().isAfter(LocalDateTime.now())) {
                BusinessLogicException.throwException(Constant.RESPONSE_CODE_31010164, "未到报名时间！");
            }
        }
        // 分别获取项目收集项id
        String nameId = projectMapper.getCollectIdByProject(ComponentNameEnum.name.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String phoneCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.phone.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String emailCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.email.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String idCardTypeId = projectMapper.getCollectIdByProject(ComponentNameEnum.certificatetype.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String idCardCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.idcard.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String birthdayCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.birthday.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String admissionnoId = projectMapper.getCollectIdByProject(ComponentNameEnum.admissionno.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
        String idcardphotoId = projectMapper.getCollectIdByProject(ComponentNameEnum.idcardphoto.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());

        // 附件id
        String enclosureId = projectMapper.getCollectIdByProject("附件", studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());

        // 是不是必选的
        String enclosureIdIsrequre = projectMapper.getCollectRequiredByProject("附件", studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());


        QueryWrapper<ProjectCollectInfo> wrapper = new QueryWrapper<ProjectCollectInfo>();
        wrapper.eq("component_name", "图片");
        wrapper.eq("project_id", studentInfoListVo.getProjectId());
        List<ProjectCollectInfo> imagelist = iProjectCollectInfoService.list(wrapper);


        String nameStr = "";
        String birthdayStr = "";
        String idcardStr = "";
        String idCardTypeStr = "";

        List<StudentInfo> list = studentInfoListVo.getList();
        boolean phoneRepeat = false;
        boolean emailRepeat = false;

        for (StudentInfo studentInfo : list) {
            if (StringUtils.isNotBlank(idCardTypeId)) {
                if (idCardTypeId.equals(studentInfo.getProjectCollectInfoId())) {
                    idCardTypeStr = studentInfo.getValue();
                }
            }
            if (StringUtils.isNotBlank(nameId)) {
                if (nameId.equals(studentInfo.getProjectCollectInfoId())) {
                    nameStr = studentInfo.getValue();
                }
            }
        }

        for (StudentInfo studentInfo : list) {
            // 附件
            if (StringUtils.isNotBlank(enclosureId)) {
                if (enclosureId.equals(studentInfo.getProjectCollectInfoId())) {
                    if (StringUtils.isEmpty(studentInfo.getValue()) && BmProjectCcollectInfoRequiredEnum.REQUIRED.getRequiredStatus().equals(enclosureIdIsrequre)) {
                        InvalidRequestException.throwException(31010156, "请选择附件");
                        break;
                    }
                }
            }
            // 图片
            if (imagelist != null && imagelist.size() > 0) {
                for (int j = 0; j < imagelist.size(); j++) {
                    String photoId = imagelist.get(j).getId();
                    String isRequired = String.valueOf(imagelist.get(j).getRequired());// 是否必填
                    Integer minUploadNum = projectMapper.getCollectUploadNumByProject(photoId);// 最少上传数量：cj_project_image_standard
                    if (StringUtils.isNotBlank(photoId)) {
                        if (photoId.equals(studentInfo.getProjectCollectInfoId())) {
                            // 必填
                            if (BmProjectCcollectInfoRequiredEnum.REQUIRED.getRequiredStatus().equals(isRequired)) {
                                if (StringUtils.isEmpty(studentInfo.getValue())) {
                                    InvalidRequestException.throwException(31010157, "照片为空");
                                    break;
                                }
                                int num = 0;
                                String[] strings = studentInfo.getValue().split(",");
                                for (String string : strings) {
                                    if (StringUtils.isNotBlank(string)) {
                                        num++;
                                    }
                                }
                                if (num < minUploadNum) {
                                    InvalidRequestException.throwException(31010157, "照片为空");
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            // 身份证照片
            if (StringUtils.isNotBlank(idcardphotoId)) {
                if (idcardphotoId.equals(studentInfo.getProjectCollectInfoId())) {
                    if (StringUtils.isEmpty(studentInfo.getValue())) {
                        String idcardphotoIsrequre = projectMapper.getCollectRequiredByProject("idcardphoto", studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
                        if (BmProjectCcollectInfoRequiredEnum.REQUIRED.getRequiredStatus().equals(idcardphotoIsrequre)) {
                            InvalidRequestException.throwException(31010158, "身份证照片为空");
                            break;
                        }
                    }
                }
            }

            // 有电话号码采集信息
            if (StringUtils.isNotBlank(phoneCollectId)) {
                if (phoneCollectId.equals(studentInfo.getProjectCollectInfoId())) {
                    String phoneCollectIdIsrequre = projectMapper.getCollectRequiredByProject(ComponentNameEnum.phone.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
                    // 如果电话号码是必填的
                    if (BmProjectCcollectInfoRequiredEnum.REQUIRED.getRequiredStatus().equals(phoneCollectIdIsrequre)) {
                        if (StringUtils.isBlank(studentInfo.getValue())) {
                            InvalidRequestException.throwException(31081106, "电话号码不能为空！请输入");
                        }
                    }
                    if (StringUtils.isNotBlank(studentInfo.getValue())) {
                        StudentInfo objInfo = studentInfoMapper.getStuByCollectId(phoneCollectId, studentInfoListVo.getProjectId(), studentInfo.getValue());
                        if (objInfo != null) {
                            phoneRepeat = true;
                            // 手机有重复
                            continue;
                        }
                    }
                }
            }

            // 有邮箱采集信息
            if (StringUtils.isNotBlank(emailCollectId)) {
                if (emailCollectId.equals(studentInfo.getProjectCollectInfoId())) {
                    String emailCollectIdIsrequre = projectMapper.getCollectRequiredByProject(ComponentNameEnum.email.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
                    if (BmProjectCcollectInfoRequiredEnum.REQUIRED.getRequiredStatus().equals(emailCollectIdIsrequre)) {
                        if (StringUtils.isBlank(studentInfo.getValue())) {
                            InvalidRequestException.throwException(31081107, "邮箱不能为空！请输入！");
                        }
                    }
                    if (StringUtils.isNotBlank(studentInfo.getValue())) {
                        StudentInfo objInfo = studentInfoMapper.getStuByCollectId(emailCollectId, studentInfoListVo.getProjectId(), studentInfo.getValue());
                        if (objInfo != null) {
                            emailRepeat = true;
                            // email有重复
                            continue;
                        }
                    }
                }
            }

            if (StringUtils.isNotBlank(admissionnoId)) {
                if (admissionnoId.equals(studentInfo.getProjectCollectInfoId())) {
                    String admissionnoIdIsrequre = projectMapper.getCollectRequiredByProject(ComponentNameEnum.admissionno.getCode(), studentInfoListVo.getProjectId(), DelFlagEnum.NORMAL.getCode());
                    if (BmProjectCcollectInfoRequiredEnum.REQUIRED.getRequiredStatus().equals(admissionnoIdIsrequre)) {
                        try {
                            CheckUtil.check(studentInfo.getValue(), "准考证号", StrRuler.admissionNo());
                        } catch (CheckException e) {
                            InvalidRequestException.throwException(31011154, "准考证号不符合规范，请重新输入");
                            // 准考证号码重复
                            continue;
                        }
                    }
                    if (StringUtils.isNotBlank(studentInfo.getValue())) {
                        StudentInfo objInfo = studentInfoMapper.getStuByCollectId(admissionnoId, studentInfoListVo.getProjectId(), studentInfo.getValue());
                        if (objInfo != null) {
                            InvalidRequestException.throwException(31011153, "准考证号存在，请重新输入");
                            // 准考证号码重复
                            continue;
                        }
                    }
                }
            }

            if (StringUtils.isNotBlank(idCardCollectId)) {
                if (idCardCollectId.equals(studentInfo.getProjectCollectInfoId())) {
                    StudentInfo objInfo = studentInfoMapper.getStuByCollectId(idCardCollectId, studentInfoListVo.getProjectId(), studentInfo.getValue());
                    if (objInfo != null) {
                        InvalidRequestException.throwException(31010119, "身份证号码已存在");
                        // 证件号码有重复
                        continue;
                    }
                    // 判断是否非开放性报名
                    if (0 == project.getIsOpen()) {
                        NonOpenInfo nonOpenInfo = nonOpenMapper.queryStudentByCardNum(studentInfoListVo.getProjectId(), studentInfo.getValue());
                        if (nonOpenInfo == null) {
                            InvalidRequestException.throwException(31010159, "抱歉，您暂时没有报名资格！");
                        } else {
                            if (!nameStr.equals(nonOpenInfo.getStudentName()) || !studentInfo.getValue().equals(nonOpenInfo.getCardNumber())) {
                                InvalidRequestException.throwException(31010160, "姓名与报名资格导入姓名不符！");
                            }
                        }
                    }
                    // 如果是身份证
                    if (StringUtils.isNotBlank(idCardTypeStr) && CertificateTypeEnum.IDCARD.getType().equals(idCardTypeStr)) {
                        String tipInfo = IDCardUtil.IdCardValidate(studentInfo.getValue());
                        idcardStr = studentInfo.getValue();
                        if (!"YES".equals(tipInfo)) {
                            InvalidRequestException.throwException(31010118, "身份证不合法");
                            // 身份证不合法
                            continue;
                        }
                    } else if (StringUtils.isNotBlank(idCardTypeStr) && CertificateTypeEnum.HONGKONGMACAOANDTAIWANIDCARD.getType().equals(idCardTypeStr)) {
                        if (!idCardTypeStr.matches(Constant.HKMACAOTAWAN)) {
                            InvalidRequestException.throwException(31010118, "身份证不合法");
                            continue;
                        }
                    }

                }
            }
            if (CertificateTypeEnum.IDCARD.getType().equals(idCardTypeStr)) {
                if (StringUtils.isNotBlank(birthdayCollectId)) {
                    if (birthdayCollectId.equals(studentInfo.getProjectCollectInfoId())) {
                        // 出生日期
                        if (StringUtils.isNotBlank(studentInfo.getValue())) {
                            String cs = studentInfo.getValue() + " 00:00:00";
                            DateFormat format1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                            Date csTime = null;
                            try {
                                csTime = format1.parse(cs);
                            } catch (ParseException e) {
                                log.error("日期转换异常", e);
                            }
                            birthdayStr = DateUtil.dateToStrF(csTime);
                            Date currentTime = new Date();
                            if (csTime != null && currentTime != null) {
                                if (csTime.getTime() > currentTime.getTime()) {
                                    InvalidRequestException.throwException(31010154, "出生日期不能是当前时间之后，请重新输入");
                                    // 出生日期大于当前时间
                                    continue;
                                }
                            }
                        }
                    }
                }
            }

        }

        if (!StringUtils.isBlank(idcardStr) && !StringUtils.isBlank(birthdayStr)) {
            if (idcardStr.length() > 14) {
                String tempstr = idcardStr.substring(6, 14);
                if (!tempstr.equals(birthdayStr.replaceAll("-", ""))) {
                    InvalidRequestException.throwException(31010155, "输入的出生日期和证件号码不一致，请重新输入");
                }
            }
        }
        // 手机+邮箱 重复
        if (emailRepeat && phoneRepeat) {
            InvalidRequestException.throwException(31010153, "手机号、邮箱已存在，请重新输入");
        }

        // 校验必填数据的完整性
        this.validateRequiredData(studentInfoListVo.getProjectId(), studentInfoListVo.getList());
    }

    @Override
    public List<StudentInfo> getByProjectId(String projectId) {
        return studentInfoMapper.getByProjectId(projectId);
    }

    @Override
    public String uploadEnclosureFile(MultipartFile multipartFile, String projectCollectInfoId) {
        QueryWrapper<ProjectImageStandard> wrapper = new QueryWrapper<ProjectImageStandard>();
        wrapper.eq("project_collect_info_id", projectCollectInfoId);
        ProjectImageStandard projectImageStandard = iProjectImageStandardService.getOne(wrapper);

        try {
            long size = multipartFile.getSize(); // kb
            double fileSize = (double) size / (1024.00 * 1024); // M
            if (fileSize > Double.valueOf(projectImageStandard.getMaxSize()) || fileSize < Double.valueOf(projectImageStandard.getMinSize())) { // 判断附件大小
                return "附件不合适.范围:" + projectImageStandard.getMinSize() + "- " + projectImageStandard.getMaxSize();
            }
        } catch (Exception e) {
            if (log.isDebugEnabled()) {
                log.debug("# uploadEnclosureFile error", e);
            }
            return e.toString();
        }
        return "";
    }

    /*****
     *
     * 集体报名导入
     *
     */
    @SneakyThrows
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importMulFile(MultipartFile file, String officeId, String projectId, Boolean createUser, User user) {
        // 按照文件名做科目切分
        String fileName = file.getOriginalFilename();
        List<ProjectSubject> allsubjectList = projectSubjectMapper.querySubjectList(projectId, null);
        List<ProjectSubject> subjectListByFileName = getSubjectListByFileName(fileName, allsubjectList);
        ProgressManager.updateProgressCurrent(5, "获取所有科目完成");

        // 校验科目数
        Project project = projectMapper.selectById(projectId);
        checkProjectAndSubject(subjectListByFileName, project);
        ProgressManager.updateProgressCurrent(10, "校验科目数完成");

        // title与对应的采集信息数据
        List<ProjectCollectInfoVo> volist = iProjectCollectInfoService.queryBaseCj(projectId);
        Map<String, ProjectCollectInfoVo> tempmap = volist.stream().collect(Collectors.toMap(ProjectCollectInfo::getTitle, Function.identity()));
        ProgressManager.updateProgressCurrent(15, "获取文件采集信息头完成");

        // 构建数据标识
        ProjectStudentImportRecordParam recordParam = ProjectStudentImportRecordParam.buildParamsFlag(volist);
        if (createUser && !(recordParam.getPhoneflag() || recordParam.getEmailflag())) {
            throw new InvalidRequestException(31811112, "需要创建账号，但是文件中缺少电话号码或者邮箱采集数据，请重新导入！");
        }
        ProgressManager.updateProgressCurrent(20, "构建数据标识完成");

        ExcelDto excelDto = EasyexcelUtil.getExcelDataList(file.getInputStream());
        List<Map<String, String>> rowDataList = excelDto.getRowDataList();
        if (CollectionUtils.isEmpty(rowDataList)) {
            throw new InvalidRequestException(31811116, "解析导入数据表内容为空，请完整内容重新导入！");
        }
        ProgressManager.updateProgressCurrent(25, "Excel文件数据解析完成");

        // 校验手机号或者身份证是否重复
        ApiResponse<?> apiResponse = checkRepeat(projectId, recordParam.getPhoneflag(), recordParam.getEmailflag(), recordParam.getAdmissionnoflag(), recordParam.getIdcardflag(), rowDataList);
        if (apiResponse.getCode() != Constant.RESPONSE_CODE_SUCCESS) {
            throw new InvalidRequestException(apiResponse.getCode(), (String) apiResponse.getData());
        }
        ProgressManager.updateProgressCurrent(30, "校验手机号与证件号完成");

        // 表头多少列
        Map<Integer, String> headMap = excelDto.getHeadMap();
        int firstRowColNum = headMap.size();
        boolean unAvailableDate = true;
        for (int i = 0; i < firstRowColNum; i++) {
            String title = headMap.get(i).trim();
            if (StringUtils.isNotEmpty(title)) {
                // 判断模板是否正确
                if (tempmap.get(title) == null) {
                    BusinessLogicException.throwException(31811102, "文件内容存在空数据，请检查文件内容后重新导入！");
                }
                unAvailableDate = false;
            }
        }
        if (unAvailableDate) {
            BusinessLogicException.throwException(31811102, "文件内容存在空数据，请检查文件内容后重新导入！");
        }
        ProgressManager.updateProgressCurrent(35, "Excel文件数据校验完成");

        List<StudentSubject> studentSubjectList = new ArrayList<>();
        // 所有的考生信息map
        Map<String, List<StudentInfo>> studentInfoListMap = new HashMap<>();
        // 所有的考生信息集合
        List<StudentInfo> studentInfoList = new ArrayList<>();
        List<StudentProject> studentProjectList = new ArrayList<>();
        // 开始解析数据表
        for (Map<String, String> rowDataL : rowDataList) {
            StudentProject studentProject = createStudentProject(projectId, project, user);
            studentProjectList.add(studentProject);

            rowDataL.put("id", studentProject.getId());
            List<StudentInfo> studentInfoListTemp = new ArrayList<>();
            for (Map.Entry<Integer, String> entey : headMap.entrySet()) {
                Boolean valueIsRequre = Boolean.TRUE;
                ProjectCollectInfoVo projectCollectInfoVo = tempmap.get(entey.getValue());
                if (null != projectCollectInfoVo && !projectCollectInfoVo.getRequired().equals(1)) {
                    valueIsRequre = Boolean.FALSE;
                }
                if (valueIsRequre && StringUtils.isEmpty(rowDataL.get(entey.getValue()))) {
                    BusinessLogicException.throwException(31811102, "文件内容存在空数据，请检查文件内容后重新导入！");
                }
                if (StringUtils.isEmpty(rowDataL.get(entey.getValue()))) {
                    continue;
                }
                String value = rowDataL.get(entey.getValue()).trim();
                StudentInfo info = createStudentInfo(projectId, createUser, studentProject, projectCollectInfoVo, value, user.getId());
                studentInfoListTemp.add(info);
            }
            studentInfoList.addAll(studentInfoListTemp);
            studentInfoListMap.put(studentProject.getId(), studentInfoListTemp);
            if (CollectionUtils.isNotEmpty(subjectListByFileName)) {
                for (int n = 0; n < subjectListByFileName.size(); n++) {
                    StudentSubject studentSubject = createStudentSubject(projectId, subjectListByFileName.get(n), studentProject, user.getId());
                    studentSubjectList.add(studentSubject);
                }
            }
            //加入考生的名字，手机，证件类型，证件号, 如果有office采集信息，需要处理归属部门
            ansycStudentInfo(studentInfoListTemp, projectId, studentProject);
        }
        ProgressManager.updateProgressCurrent(40, "Excel文件数据检查通过");

        if (CollectionUtils.isNotEmpty(studentProjectList)) {
            batchSaveStudent(studentProjectList);
        }
        ProgressManager.updateProgressCurrent(45, "批量新增考生数据入库完成");

        Map<String, Integer> subjectRegiestCount = new HashMap<>();
        Map<String, Integer> subjectConfigCount = new HashMap<>();
        Map<String, Boolean> validateCount = new HashMap<>();

        if (CollectionUtils.isNotEmpty(studentSubjectList)) {
            // 校验科目数报名人数设置 和实际报名人数对比
            for (ProjectSubject projectSubject : subjectListByFileName) {
                int count = 0;
                for (StudentSubject studentProject : studentSubjectList) {
                    if (studentProject.getSubjectId().equals(projectSubject.getSubjectId())) {
                        count++;
                    }
                }
                subjectRegiestCount.put(projectSubject.getSubjectId(), count);
                subjectConfigCount.put(projectSubject.getSubjectId(), projectSubject.getMaxNumberofRegister());
                validateCount.put(projectSubject.getSubjectId(), projectSubject.getLimitSubjectRegister() == 0 ? false : true);
            }

            if (MapUtil.isNotEmpty(subjectRegiestCount)) {
                for (String subjectId : subjectRegiestCount.keySet()) {
                    // 导入的数量
                    Integer importCount = subjectRegiestCount.get(subjectId);
                    // 获取当前数据库科目报名人数
                    Integer dbCount = studentSubjectMapper.countStudentSubject(projectId, subjectId);
                    if (null == dbCount) dbCount = Integer.valueOf(0);
                    // 设置的数量
                    Integer configCount = subjectConfigCount.get(subjectId);

                    Boolean validataCount = validateCount.get(subjectId);
                    if (validataCount && (importCount + dbCount) > configCount) {
                        throw new InvalidRequestException(31811118, "导入考生报考科目的数量大于科目最大报名人数，请重新导入！");
                    }
                }
            }
            batchSaveStudentSubject(studentSubjectList);
        }
        ProgressManager.updateProgressCurrent(60, "考生科目入库完成");

        if (CollectionUtils.isNotEmpty(studentInfoList)) {
            log.info("[导入考生信息] 集体报名studentInfoList-size:{}", studentInfoList.size());
            batchSaveStudentInfo(studentInfoList);
        }

        ProgressManager.updateProgressCurrent(80L, "考生采集信息入库完成");
        log.info("[导入考生信息] 集体报名完成 %{}", 80L);

        if (createUser) {
            log.info("[导入考生信息] 开始集体报名创建账号,size:[{}]", rowDataList.size());
            for (int i = 0; i < rowDataList.size(); i++) {
                GroupRegistrationExamineeInfo groupRegistrationExamineeInfo = new GroupRegistrationExamineeInfo();

                Map<String, String> map = rowDataList.get(i);
                String studentId = map.get("id");
                groupRegistrationExamineeInfo.setStudentId(studentId);

                ExamineeRegisterVO examineeRegisterVO = createExamineeRegisterVO(officeId, recordParam, map);
                groupRegistrationExamineeInfo.setExamineeRegisterVO(examineeRegisterVO);

                log.info("[导入考生信息] 开始集体报名创建账号,sendMessage:[{}]", FastJsonUtil.getBeanToJson(groupRegistrationExamineeInfo));
                groupRegistrationDataProducer.sendMessage(groupRegistrationExamineeInfo);
                log.info("[导入考生信息] 开始集体报名创建账号,sendMessage success");
            }
        }
        ProgressManager.finish(null);
        log.info("[导入考生信息]集体报名完成 %{}", 100L);

    }

    @Override
    public ExamineeRegisterVO createExamineeRegisterVO(String officeId, ProjectStudentImportRecordParam recordParam, Map<String, String> map) {
        ExamineeRegisterVO examineeRegisterVO = new ExamineeRegisterVO();
        examineeRegisterVO.setOfficeid(officeId);
        if (recordParam.getPhoneflag()) {
            examineeRegisterVO.setContent(map.get("手机号"));
            examineeRegisterVO.setName(map.get("姓名"));
            examineeRegisterVO.setOfficeid(officeId);
            examineeRegisterVO.setPassword(map.get("手机号"));
        } else if (recordParam.getEmailflag()) {
            examineeRegisterVO.setContent(map.get("邮箱"));
            examineeRegisterVO.setName(map.get("姓名"));
            examineeRegisterVO.setOfficeid(officeId);
            examineeRegisterVO.setPassword(map.get("邮箱"));
        }
        return examineeRegisterVO;
    }

    private StudentInfoListVo createStudentInfoListVo(String projectId, StudentProject studentProject, List<StudentInfo> studentInfoListTemp) {
        StudentInfoListVo studentInfoListVo = new StudentInfoListVo();
        studentInfoListVo.setList(studentInfoListTemp);
        studentInfoListVo.setStudentId(studentProject.getId());
        studentInfoListVo.setRegId(studentProject.getRegId());
        studentInfoListVo.setCreateFlag(true);
        studentInfoListVo.setProjectId(projectId);
        return studentInfoListVo;
    }

    private void batchSaveStudentInfo(List<StudentInfo> studentInfoList) {
        List<List<StudentInfo>> partitionStudentInfos = Lists.partition(studentInfoList, configManager.getBatchSaveSize());
        // 如果数据量比较大的话，分组修改1000一组
        if (CollectionUtils.isNotEmpty(partitionStudentInfos)) {
            for (List<StudentInfo> studentInfos : partitionStudentInfos) {
                saveBatch(studentInfos);

            }
        }
        ProgressManager.updateProgressCurrent(70L, null);
    }


    private void batchSaveStudentSubject(List<StudentSubject> studentSubjectList) {
        List<List<StudentSubject>> partitionAdmissions = Lists.partition(studentSubjectList, configManager.getBatchSaveSize());
        // 如果数据量比较大的话，分组修改1000一组
        if (CollectionUtils.isNotEmpty(partitionAdmissions)) {
            for (List<StudentSubject> studentSubjects : partitionAdmissions) {
                iStudentSubjectService.saveBatch(studentSubjects);
            }
        }
    }

    private void batchSaveStudent(List<StudentProject> studentProjectList) {
        List<List<StudentProject>> partitionAdmissions = Lists.partition(studentProjectList, configManager.getBatchSaveSize());
        // 如果数据量比较大的话，分组修改1000一组
        if (CollectionUtils.isNotEmpty(partitionAdmissions)) {
            for (List<StudentProject> studentProjects : partitionAdmissions) {
                iStudentProject.saveBatch(studentProjects);
            }
        }
    }

    private static StudentSubject createStudentSubject(String projectId, ProjectSubject projectSubject, StudentProject studentProject, String userId) {
        LocalDateTime now = LocalDateTime.now();
        StudentSubject studentSubject = new StudentSubject();
        studentSubject.setSubjectId(projectSubject.getSubjectId());
        studentSubject.setStudentId(studentProject.getId());
        studentSubject.setSubjectName(projectSubject.getSubjectName());
        studentSubject.setProjectId(projectId);
        studentSubject.setPay(0);
        studentSubject.setIsPay(projectSubject.getIsPay());
        studentSubject.setCreateDate(now);
        studentSubject.setUpdateDate(now);
        studentSubject.setCreateBy(userId);
        studentSubject.setUpdateBy(userId);
        return studentSubject;
    }

    /**
     * 装配考生信息实体
     *
     * @param projectId
     * @param createUser
     * @param studentProject
     * @param projectCollectInfoVo
     * @param value
     * @param userId
     * @return
     */
    private StudentInfo createStudentInfo(String projectId, Boolean createUser, StudentProject studentProject, ProjectCollectInfoVo projectCollectInfoVo, String value, String userId) {
        StudentInfo info = new StudentInfo();
        info.setValue(value);
        // 校验和装配数据格式
        validateDataFormat(createUser, value, projectCollectInfoVo, info);
        info.setProjectCollectInfoId(projectCollectInfoVo.getId());
        info.setStudentId(studentProject.getId());
        info.setProjectCollectInfoName(projectCollectInfoVo.getTitle());
        info.setProjectId(projectId);
        info.setId(UUIDUtils.newSortUUID());
        info.setCreateBy(userId);
        info.setUpdateBy(userId);
        return info;
    }

    /**
     * 装配考生报名关联信息
     *
     * @param projectId
     * @param project
     * @return
     */
    private StudentProject createStudentProject(String projectId, Project project, User user) {
        LocalDateTime now = LocalDateTime.now();
        String studentId = UUIDUtils.newSortUUID();
        StudentProject studentProject = new StudentProject();
        studentProject.setIsAudit(BmAuditStatusEnum.APPROVED.getAuditStatus());
        studentProject.setId(studentId);
        studentProject.setProjectId(projectId);
        studentProject.setOfficeId(user.getOfficeid());
        studentProject.setDeptId(user.getOrganizationid());
        studentProject.setCreateDate(now);
        studentProject.setUpdateDate(now);
        studentProject.setCreateBy(user.getId());
        studentProject.setUpdateBy(user.getId());
        return studentProject;
    }

    private void checkProjectAndSubject(List<ProjectSubject> subjectListByFileName, Project project) {
        if (Objects.isNull(project)) {
            throw new InvalidRequestException(Constant.RESPONSE_CODE_31010110, "当前操作的报名项目不存在");
        }
        if (CollectionUtils.isNotEmpty(subjectListByFileName)) {
            // 首先校验报名科目是否和最大报考科目一致
            if (project.getMaxSubject() < subjectListByFileName.size()) {
                InvalidRequestException.throwException(31081204, "集体报名报考科目数量与当前最多报名科目数不匹配！");
            }
        } else {
            // 首先校验报名科目是否和最大报考科目一致
            Integer subjectTotal = iProjectSubjectService.lambdaQuery()
                    .eq(ProjectSubject::getProjectId, project.getId())
                    .eq(BaseEntity::getDelFlag, Boolean.FALSE)
                    .count();

            if (!NumberUtil.equals(project.getMaxSubject(), subjectTotal)) {
                throw new InvalidRequestException(31081204, "集体报名默认报考所有科目，当前最多报名科目数与总科目数不匹配");
            }
        }
    }

    /**
     * 验证数据格式
     *
     * @param createUser
     * @param studentValue
     * @param tempVo
     * @param info
     */
    private void validateDataFormat(Boolean createUser, String studentValue, ProjectCollectInfoVo tempVo, StudentInfo info) {
        // 如果是组织机构需要设置层级结构
        if (ComponentNameEnum.office.getDesc().equals(tempVo.getTitle())) {
            if (CollectionUtils.isNotEmpty(tempVo.getOptionList())) {
                ProjectCollectInfoOption projectCollectInfoOption = null;
                for (int k = 0; k < tempVo.getOptionList().size(); k++) {
                    if (studentValue.equals(tempVo.getOptionList().get(k).getOptionLabel())) {
                        projectCollectInfoOption = tempVo.getOptionList().get(k);
                        studentValue = projectCollectInfoOption.getOptionValue();
                    }
                }
                if (null == projectCollectInfoOption) {
                    String exceptionMessage = StrUtil.format("文件采集内容<{}>与组织机构采集信息定义不一致", studentValue);
                    BusinessLogicException.throwException(ProgressConstant.RESPONSE_CODE_BUSINESS_ERROR, exceptionMessage);
                }
                // 如果下拉复选的层级为空，则生成层级结构数据落库
                if (StrUtil.isBlank(projectCollectInfoOption.getOptionLevel())) {
                    studentValue = getOptionsLevelValue(studentValue, projectCollectInfoOption, tempVo.getOptionList());
                }
                info.setValue(studentValue);
            }
        } else {
            if (CollectionUtils.isNotEmpty(tempVo.getOptionList())) {
                ProjectCollectInfoOption projectCollectInfoOption = null;
                for (int k = 0; k < tempVo.getOptionList().size(); k++) {
                    if (studentValue.equals(tempVo.getOptionList().get(k).getOptionLabel())) {
                        projectCollectInfoOption = tempVo.getOptionList().get(k);
                        studentValue = tempVo.getOptionList().get(k).getOptionValue();
                    }
                }
                if (null == projectCollectInfoOption) {
                    String exceptionMessage = StrUtil.format("文件采集内容<{}>与{}采集信息定义不一致", studentValue, tempVo.getTitle());
                    BusinessLogicException.throwException(ProgressConstant.RESPONSE_CODE_BUSINESS_ERROR, exceptionMessage);
                }
                // 如果是下拉级联组件，需要设置层级结构
                if (StrUtil.equals(tempVo.getComponentType(), ComponentTypeEnum.cascader.getType())) {
                    // 如果下拉复选的层级为空，则生成层级结构数据落库
                    if (StrUtil.isBlank(projectCollectInfoOption.getOptionLevel())) {
                        studentValue = getOptionsLevelValue(studentValue, projectCollectInfoOption, tempVo.getOptionList());
                    }
                }
                info.setValue(studentValue);
            }

        }
        // 校验数据是不是合法
        // 证件是不是合法
        boolean idCard = false;
        if (ComponentNameEnum.idcard.getDesc().equals(tempVo.getTitle())) {
            // 校验身份证是否在有效期
            String tipInfo = IDCardUtil.IdCardValidate(studentValue);
            if (!IDCardUtil.TIPINFO.equals(tipInfo)) {
                idCard = true;
            }
            if (idCard && !studentValue.matches(Constant.HKMACAOTAWAN)) {
                idCard = true;
            } else {
                idCard = false;
            }
        }
        if (idCard) {
            String exceptionMessage = StrUtil.format("证件号码<{}>存在格式不正确，请检查文件后重新导入", studentValue);
            BusinessLogicException.throwException(ProgressConstant.RESPONSE_CODE_BUSINESS_ERROR, exceptionMessage);
        }
        // 准考证是不是合法
        boolean admissionFlag = false;
        if (ComponentNameEnum.admissionno.getDesc().equals(tempVo.getTitle())) {
            try {
                CheckUtil.check(studentValue, "准考证号", StrRuler.admissionNo());
            } catch (CheckException e) {
                admissionFlag = true;
            }
        }
        if (admissionFlag) {
            String exceptionMessage = StrUtil.format("准考证号码<{}>存在格式不正确，请检查文件后重新导入", studentValue);
            BusinessLogicException.throwException(ProgressConstant.RESPONSE_CODE_BUSINESS_ERROR, exceptionMessage);
        }

        // 如果需要创建账号
        if (ComponentNameEnum.phone.getDesc().equals(tempVo.getTitle())) {
            try {
                CheckUtil.check(studentValue, "电话号码", StrRuler.phone());
            } catch (CheckException e) {
                String exceptionMessage = StrUtil.format("电话号码<{}>存在格式不正确，请检查文件后重新导入", studentValue);
                BusinessLogicException.throwException(ProgressConstant.RESPONSE_CODE_BUSINESS_ERROR, exceptionMessage);
            }
        }
        if (ComponentNameEnum.email.getDesc().equals(tempVo.getTitle())) {
            try {
                CheckUtil.check(studentValue, "邮箱", StrRuler.email());
            } catch (CheckException e) {
                String exceptionMessage = StrUtil.format("邮箱<{}>存在格式不正确，请检查文件后重新导入", studentValue);
                BusinessLogicException.throwException(ProgressConstant.RESPONSE_CODE_BUSINESS_ERROR, exceptionMessage);
            }
        }

        if (ComponentNameEnum.birthday.getDesc().equals(tempVo.getTitle())) {
            try {
                DateTime dateTime = cn.hutool.core.date.DateUtil.parse(studentValue);
                info.setValue(dateTime.toDateStr());
            } catch (Exception e) {
                String exceptionMessage = StrUtil.format("出生日期<{}>存在格式不正确，请检查文件后重新导入", studentValue);
                BusinessLogicException.throwException(ProgressConstant.RESPONSE_CODE_BUSINESS_ERROR, exceptionMessage);
            }
        }
    }

    /**
     * 获取多级选项级别数据拼接
     *
     * @param value
     * @param projectCollectInfoOption
     * @param optionList
     * @return
     */
    private String getOptionsLevelValue(String value, ProjectCollectInfoOption projectCollectInfoOption, List<ProjectCollectInfoOption> optionList) {
        String valueTemp = value;
        for (ProjectCollectInfoOption projectCollectInfoOption2 : optionList) {
            if (StringUtils.isNotEmpty(projectCollectInfoOption.getParentOptionValue()) && StrUtil.equals(projectCollectInfoOption2.getOptionValue(), projectCollectInfoOption.getParentOptionValue())) {
                valueTemp = projectCollectInfoOption2.getOptionValue() + "," + value;
                valueTemp = getOptionsLevelValue(valueTemp, projectCollectInfoOption2, optionList);
                break;
            }
        }
        return valueTemp;
    }

    /**
     * 通过科目名称获取科目列表
     *
     * @param fileNameTemp
     * @param allsubjectList
     * @return
     */
    private List<ProjectSubject> getSubjectListByFileName(String fileNameTemp, List<ProjectSubject> allsubjectList) {
        String fileName = KqStringUtils.stripFilenameExtension(fileNameTemp);
        if (StringUtils.isEmpty(fileName) || CollectionUtils.isEmpty(allsubjectList)) {
            return Lists.newArrayList();
        }

        Map<String, ProjectSubject> projectSubjectMap = allsubjectList.stream().collect(Collectors.toMap(ProjectSubject::getSubjectName, Function.identity()));
        String[] subArry = fileName.split("_");
        List<ProjectSubject> subjectList = new ArrayList<>();
        if (subArry.length > 0) {
            for (int i = 0; i < subArry.length; i++) {
                if (projectSubjectMap.containsKey(subArry[i])) {
                    subjectList.add(projectSubjectMap.get(subArry[i]));
                }
            }
        }
        if (CollectionUtils.isNotEmpty(subjectList)) {
            return subjectList;
        } else {
            return Lists.newArrayList();
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResponse<?> createUser(String officeId, ImportStudentVo vo) {
        // 如果手机号码和邮箱都没有的话，则不创建账号信息
        if (vo != null && !vo.getPhoneflag() && !vo.getEmailflag()) {
            return ApiResponse.builder().code(Constant.RESPONSE_CODE_14072).data(vo).build();
        } else if (vo != null && CollectionUtils.isNotEmpty(vo.getResultList())) {
            for (int i = 0; i < vo.getResultList().size(); i++) {
                Map<String, String> map = vo.getResultList().get(i);
                String id = map.get("id");
                ExamineeRegisterVO examineeRegisterVO = new ExamineeRegisterVO();
                examineeRegisterVO.setOfficeid(officeId);
                if (vo.getPhoneflag()) {
                    examineeRegisterVO.setContent(map.get("手机号"));
                    examineeRegisterVO.setName(map.get("姓名"));
                    examineeRegisterVO.setOfficeid(officeId);
                    examineeRegisterVO.setPassword(configManager.getBmreguserpwdprefix() + map.get("手机号"));
                } else if (vo.getEmailflag()) {
                    examineeRegisterVO.setContent(map.get("邮箱"));
                    examineeRegisterVO.setName(map.get("姓名"));
                    examineeRegisterVO.setOfficeid(officeId);
                    examineeRegisterVO.setPassword(map.get("邮箱"));
                }
                GroupRegistrationExamineeInfo groupRegistrationExamineeInfo = new GroupRegistrationExamineeInfo();
                groupRegistrationExamineeInfo.setExamineeRegisterVO(examineeRegisterVO);
                groupRegistrationExamineeInfo.setStudentId(id);
                groupRegistrationDataProducer.sendMessage(groupRegistrationExamineeInfo);
            }
        }
        return ApiResponse.builder().code(Constant.RESPONSE_CODE_SUCCESS).data(vo).build();
    }


    public ApiResponse<?> checkRepeat(String projectId, boolean phoneflag, boolean emailflag, boolean admissionnoflag, boolean idcardflag, List<Map<String, String>> studentMaps) {
        String columns = projectSubjectMapper.getBaseCjSqlColumn(projectId);
        // 电话号码
        HashMap<String, Integer> phoneMap = new HashMap<>();
        // 邮箱
        HashMap<String, Integer> emailMap = new HashMap<>();
        // 邮箱
        HashMap<String, Integer> admissionnoMap = new HashMap<>();
        // 身份证
        HashMap<String, Integer> idCardMap = new HashMap<>();
        // 港澳台
        HashMap<String, Integer> gatCardMap = new HashMap<>();
        // 护照
        HashMap<String, Integer> otherCardMap = new HashMap<>();

        // 查询考生信息列表
        if (StringUtils.isNotEmpty(columns)) {
            List<Map<String, Object>> listMaps = projectSubjectMapper.queryAllStudent(columns, projectId, null, null, null);
            // 存在考生信息
            if (CollectionUtils.isNotEmpty(listMaps)) {
                for (int i = 0; i < listMaps.size(); i++) {
                    if (phoneflag) {
                        if (listMaps.get(i).get(ComponentNameEnum.phone.getDesc()) != null) {
                            if (phoneMap.get(listMaps.get(i).get(ComponentNameEnum.phone.getDesc())) == null) {
                                phoneMap.put(listMaps.get(i).get(ComponentNameEnum.phone.getDesc()).toString(), 1);
                            } else {
                                phoneMap.put(listMaps.get(i).get(ComponentNameEnum.phone.getDesc()).toString(), phoneMap.get(listMaps.get(i).get(ComponentNameEnum.phone.getDesc())) + 1); // 如果有则
                                // 次数加一
                            }
                        }
                    }
                    if (emailflag) {
                        if (listMaps.get(i).get(ComponentNameEnum.email.getDesc()) != null) {
                            if (emailMap.get(listMaps.get(i).get(ComponentNameEnum.email.getDesc())) == null) {
                                emailMap.put(listMaps.get(i).get(ComponentNameEnum.email.getDesc()).toString(), 1);
                            } else {
                                emailMap.put(listMaps.get(i).get(ComponentNameEnum.email.getDesc()).toString(), emailMap.get(listMaps.get(i).get(ComponentNameEnum.email.getDesc())) + 1); // 如果有则
                                // 次数加一
                            }
                        }
                    }
                    if (admissionnoflag) {
                        if (listMaps.get(i).get(ComponentNameEnum.admissionno.getDesc()) != null) {
                            if (admissionnoMap.get(listMaps.get(i).get(ComponentNameEnum.admissionno.getDesc())) == null) {
                                admissionnoMap.put(listMaps.get(i).get(ComponentNameEnum.admissionno.getDesc()).toString(), 1);
                            } else {
                                admissionnoMap.put(listMaps.get(i).get(ComponentNameEnum.admissionno.getDesc()).toString(),
                                        emailMap.get(listMaps.get(i).get(ComponentNameEnum.admissionno.getDesc())) + 1); // 如果有则
                            }
                        }
                    }
                    // 有证件号码
                    if (idcardflag) {
                        if (listMaps.get(i).get(ComponentNameEnum.idcard.getDesc()) != null && CertificateTypeEnum.IDCARD.getType().equals(listMaps.get(i).get(ComponentNameEnum.certificatetype.getDesc()).toString())) {
                            if (listMaps.get(i).get(ComponentNameEnum.idcard.getDesc()) != null) {
                                if (idCardMap.get(listMaps.get(i).get(ComponentNameEnum.idcard.getDesc())) == null) {
                                    idCardMap.put(listMaps.get(i).get(ComponentNameEnum.idcard.getDesc()).toString(), 1);
                                } else {
                                    idCardMap.put(listMaps.get(i).get(ComponentNameEnum.idcard.getDesc()).toString(), idCardMap.get(listMaps.get(i).get(ComponentNameEnum.idcard.getDesc())) + 1); // 如果有则
                                    // 次数加一
                                }
                            }
                        }
                        if (listMaps.get(i).get(ComponentNameEnum.idcard.getDesc()) != null && CertificateTypeEnum.HONGKONGMACAOANDTAIWANIDCARD.getType().equals(listMaps.get(i).get(ComponentNameEnum.certificatetype.getDesc()).toString())) {
                            if (listMaps.get(i).get(ComponentNameEnum.idcard.getDesc()) != null) {
                                if (gatCardMap.get(listMaps.get(i).get(ComponentNameEnum.idcard.getDesc())) == null) {
                                    gatCardMap.put(listMaps.get(i).get(ComponentNameEnum.idcard.getDesc()).toString(), 1);
                                } else {
                                    gatCardMap.put(listMaps.get(i).get(ComponentNameEnum.idcard.getDesc()).toString(), gatCardMap.get(listMaps.get(i).get(ComponentNameEnum.idcard.getDesc())) + 1); // 如果有则
                                    // 次数加一
                                }
                            }
                        }
                        if (listMaps.get(i).get(ComponentNameEnum.idcard.getDesc()) != null && CertificateTypeEnum.PASSPORT.getType().equals(listMaps.get(i).get(ComponentNameEnum.certificatetype.getDesc()).toString())) {
                            if (listMaps.get(i).get(ComponentNameEnum.idcard.getDesc()) != null) {
                                if (otherCardMap.get(listMaps.get(i).get(ComponentNameEnum.idcard.getDesc())) == null) {
                                    otherCardMap.put(listMaps.get(i).get(ComponentNameEnum.idcard.getDesc()).toString(), 1);
                                } else {
                                    otherCardMap.put(listMaps.get(i).get(ComponentNameEnum.idcard.getDesc()).toString(), otherCardMap.get(listMaps.get(i).get(ComponentNameEnum.idcard.getDesc())) + 1); // 如果有则
                                    // 次数加一
                                }
                            }
                        }
                    }
                }
            }
        }
        if (CollectionUtils.isNotEmpty(studentMaps)) {
            for (int i = 0; i < studentMaps.size(); i++) {
                if (phoneflag) {
                    if (studentMaps.get(i).get(ComponentNameEnum.phone.getDesc()) != null) {
                        if (phoneMap.get(studentMaps.get(i).get(ComponentNameEnum.phone.getDesc())) == null) {
                            phoneMap.put(studentMaps.get(i).get(ComponentNameEnum.phone.getDesc()).toString(), 1);
                        } else {
                            phoneMap.put(studentMaps.get(i).get(ComponentNameEnum.phone.getDesc()).toString(), phoneMap.get(studentMaps.get(i).get(ComponentNameEnum.phone.getDesc())) + 1); // 如果有则
                            // 次数加一
                        }
                    }
                }
                if (emailflag) {
                    if (studentMaps.get(i).get(ComponentNameEnum.email.getDesc()) != null) {
                        if (emailMap.get(studentMaps.get(i).get(ComponentNameEnum.email.getDesc())) == null) {
                            emailMap.put(studentMaps.get(i).get(ComponentNameEnum.email.getDesc()).toString(), 1);
                        } else {
                            emailMap.put(studentMaps.get(i).get(ComponentNameEnum.email.getDesc()).toString(), emailMap.get(studentMaps.get(i).get(ComponentNameEnum.email.getDesc())) + 1); // 如果有则
                            // 次数加一
                        }
                    }
                }

                if (admissionnoflag) {
                    if (studentMaps.get(i).get(ComponentNameEnum.admissionno.getDesc()) != null) {
                        if (admissionnoMap.get(studentMaps.get(i).get(ComponentNameEnum.admissionno.getDesc())) == null) {
                            admissionnoMap.put(studentMaps.get(i).get(ComponentNameEnum.admissionno.getDesc()).toString(), 1);
                        } else {
                            admissionnoMap.put(studentMaps.get(i).get(ComponentNameEnum.admissionno.getDesc()).toString(),
                                    admissionnoMap.get(studentMaps.get(i).get(ComponentNameEnum.admissionno.getDesc())) + 1); // 如果有则
                            // 次数加一
                        }
                    }
                }
                if (idcardflag) {
                    if (studentMaps.get(i).get(ComponentNameEnum.idcard.getDesc()) != null && "大陆居民身份证".equals(studentMaps.get(i).get(ComponentNameEnum.certificatetype.getDesc()).toString())) {
                        if (studentMaps.get(i).get(ComponentNameEnum.idcard.getDesc()) != null) {
                            if (idCardMap.get(studentMaps.get(i).get(ComponentNameEnum.idcard.getDesc())) == null) {
                                idCardMap.put(studentMaps.get(i).get(ComponentNameEnum.idcard.getDesc()).toString(), 1);
                            } else {
                                idCardMap.put(studentMaps.get(i).get(ComponentNameEnum.idcard.getDesc()).toString(), idCardMap.get(studentMaps.get(i).get(ComponentNameEnum.idcard.getDesc())) + 1); // 如果有则
                                // 次数加一
                            }
                        }
                    }
                    if (studentMaps.get(i).get(ComponentNameEnum.idcard.getDesc()) != null && "港澳台身份证".equals(studentMaps.get(i).get(ComponentNameEnum.certificatetype.getDesc()).toString())) {
                        if (studentMaps.get(i).get(ComponentNameEnum.idcard.getDesc()) != null) {
                            if (gatCardMap.get(studentMaps.get(i).get(ComponentNameEnum.idcard.getDesc())) == null) {
                                gatCardMap.put(studentMaps.get(i).get(ComponentNameEnum.idcard.getDesc()).toString(), 1);
                            } else {
                                gatCardMap.put(studentMaps.get(i).get(ComponentNameEnum.idcard.getDesc()).toString(), gatCardMap.get(studentMaps.get(i).get(ComponentNameEnum.idcard.getDesc())) + 1); // 如果有则
                                // 次数加一
                            }
                        }
                    }
                    if (studentMaps.get(i).get(ComponentNameEnum.idcard.getDesc()) != null && "护照".equals(studentMaps.get(i).get(ComponentNameEnum.certificatetype.getDesc()).toString())) {
                        if (studentMaps.get(i).get(ComponentNameEnum.idcard.getDesc()) != null) {
                            if (otherCardMap.get(studentMaps.get(i).get(ComponentNameEnum.idcard.getDesc())) == null) {
                                otherCardMap.put(studentMaps.get(i).get(ComponentNameEnum.idcard.getDesc()).toString(), 1);
                            } else {
                                otherCardMap.put(studentMaps.get(i).get(ComponentNameEnum.idcard.getDesc()).toString(),
                                        otherCardMap.get(studentMaps.get(i).get(ComponentNameEnum.idcard.getDesc())) + 1); // 如果有则
                                // 次数加一
                            }
                        }
                    }
                }
            }
        }

        StringBuilder phoneStr = new StringBuilder();
        for (Map.Entry<String, Integer> me : phoneMap.entrySet()) {
            if (me.getValue() > 1) {
                phoneStr.append(me.getKey());
                phoneStr.append(",");
            }
        }
        StringBuilder emailStr = new StringBuilder();
        for (Map.Entry<String, Integer> me : emailMap.entrySet()) {
            if (me.getValue() > 1) {
                emailStr.append(me.getKey());
                emailStr.append(",");
            }
        }
        StringBuilder admissionnoStr = new StringBuilder();
        for (Map.Entry<String, Integer> me : admissionnoMap.entrySet()) {
            if (me.getValue() > 1) {
                admissionnoStr.append(me.getKey());
                admissionnoStr.append(",");
            }
        }
        StringBuilder idCardStr = new StringBuilder();
        for (Map.Entry<String, Integer> me : idCardMap.entrySet()) {
            if (me.getValue() > 1) {
                idCardStr.append(me.getKey());
                idCardStr.append(",");
            }
        }
        StringBuilder gatCardStr = new StringBuilder();
        for (Map.Entry<String, Integer> me : gatCardMap.entrySet()) {
            if (me.getValue() > 1) {
                gatCardStr.append(me.getKey());
                gatCardStr.append(",");
            }
        }
        StringBuilder otherCardStr = new StringBuilder();
        for (Map.Entry<String, Integer> me : otherCardMap.entrySet()) {
            if (me.getValue() > 1) {
                otherCardStr.append(me.getKey());
                otherCardStr.append(",");
            }
        }
        String phoneStrTemp = phoneStr.toString();
        if (StringUtils.isNotBlank(phoneStrTemp) && !Objects.equals(phoneStrTemp, ",")) {
            phoneStrTemp = phoneStrTemp.substring(0, phoneStrTemp.length() - 1);
            return ApiResponse.builder().code(31811106).data("表单存在重复电话号码数据:" + phoneStrTemp).build();
        }
        String emailStrTemp = emailStr.toString();
        if (StringUtils.isNotBlank(emailStrTemp) && !Objects.equals(emailStrTemp, ",")) {
            emailStrTemp = emailStrTemp.substring(0, emailStrTemp.length() - 1);
            return ApiResponse.builder().code(31811107).data("表单存在重复邮箱数据:" + emailStrTemp).build();
        }
        String admissionnoStrTemp = admissionnoStr.toString();
        if (StringUtils.isNotBlank(admissionnoStrTemp) && !Objects.equals(admissionnoStrTemp, ",")) {
            admissionnoStrTemp = admissionnoStrTemp.substring(0, admissionnoStrTemp.length() - 1);
            return ApiResponse.builder().code(31811108).data("表单存在重复准考证号数据:" + admissionnoStrTemp).build();
        }
        String idCardStrTemp = idCardStr.toString();
        if (StringUtils.isNotBlank(idCardStrTemp) && !Objects.equals(idCardStrTemp, ",")) {
            idCardStrTemp = idCardStrTemp.substring(0, idCardStrTemp.length() - 1);
            return ApiResponse.builder().code(31811109).data("表单存在重复身份证号码数据:" + idCardStrTemp).build();
        }
        String gatCardStrTemp = gatCardStr.toString();
        if (StringUtils.isNotBlank(gatCardStrTemp) && !Objects.equals(gatCardStrTemp, ",")) {
            gatCardStrTemp = gatCardStrTemp.substring(0, gatCardStrTemp.length() - 1);
            return ApiResponse.builder().code(31811110).data("表单存在重复港澳台身份证号码数据:" + gatCardStrTemp).build();
        }
        String otherCardStrTemp = otherCardStr.toString();
        if (StringUtils.isNotBlank(otherCardStrTemp) && !Objects.equals(otherCardStrTemp, ",")) {
            otherCardStrTemp = otherCardStrTemp.substring(0, otherCardStrTemp.length() - 1);
            return ApiResponse.builder().code(31811111).data("表单存在重复护照数据:" + otherCardStrTemp).build();
        }
        return ApiResponse.builder().code(Constant.RESPONSE_CODE_SUCCESS).build();
    }

    @Override
    public List<UserPermissionStatVo> getAreaProjectStudentNum(String projectId, String collectInfoId) {
        return studentInfoMapper.getAreaProjectStudentNum(projectId, collectInfoId);
    }

    @Override
    public Optional<UserPermissionStatVo> getNonAreaProjectStudentNum(String projectId, String deptId) {
        return studentInfoMapper.getNonAreaProjectStudentNum(projectId, deptId);
    }

    @Override
    public void assembleCandidateInfo(PushCandidateParam param) {
        List<Candidate> candidateList = param.getCandidateList();
        // 同步考生不为空
        if (CollUtil.isNotEmpty(candidateList)) {
            // 查询考生信息
            List<CandidateInfo> candidateInfoList = candidateList.stream()
                    .parallel()
                    .map(Candidate::getBmStudentId)
                    .flatMap(studentId -> this.lambdaQuery()
                            .eq(StudentInfo::getStudentId, studentId)
                            .eq(BaseEntity::getDelFlag, Boolean.FALSE)
                            .list()
                            .stream())
                    .map(data -> BeanUtil.toBean(data, CandidateInfo.class))
                    .collect(Collectors.toList());
            param.setCandidateInfoList(candidateInfoList);
        }
    }

    @Override
    public List<StudentInfo> queryAllStudentInfo(String projectId, String isPay, String isAudit, int infoPageNo, int pageSize) {
        return getBaseMapper().queryAllStudentInfo(projectId, isPay, isAudit, infoPageNo, pageSize);
    }

    @SneakyThrows
    @Override
    public ApiResponse<Object> newQuery(String projectId, String studentId) {
        if (StringUtils.isEmpty(projectId)) {
            return ApiResponse.builder().code(Constant.RESPONSE_CODE_31010136).data(null).build();
        }
        Project project = iProjectService.getById(projectId);
        if (null == project) {
            return ApiResponse.builder().code(Constant.RESPONSE_CODE_31010136).data(null).build();
        }
        List<StudentInfoVo> studentInfos = new ArrayList<>();
        if (StrUtil.isNotBlank(studentId)) {
            studentInfos = getByStudentId(projectId, studentId);
        }
        // 如果查询不到考生信息，说明未报过名
        if (CollUtil.isEmpty(studentInfos)) {
            // 判断是不是已经截止了
            LocalDateTime projectEndDate = project.getEndTime();
            if (projectEndDate.compareTo(LocalDateTime.now()) < 0) {
                return ApiResponse.builder().code(31081131).data(null).build();
            }
        }
        List<ProjectCollectInfoVo> collectInfoVoList = iProjectCollectInfoService.queryByProjectId(projectId);
        String birthdayId = StringUtils.EMPTY;
        for (ProjectCollectInfoVo vo : collectInfoVoList) {

            if (ComponentNameEnum.birthday.getCode().equals(vo.getComponentName())) {
                birthdayId = vo.getId();
            }
        }
        if (CollUtil.isNotEmpty(studentInfos)) {
            for (StudentInfoVo studentInfo : studentInfos) {
                if (birthdayId.equals(studentInfo.getProjectCollectInfoId())) {
                    if (StringUtils.isNotBlank(studentInfo.getValue())) {
                        studentInfo.setValue(studentInfo.getValue().substring(0, 10));
                    }
                }
                for (ProjectCollectInfoVo vo : collectInfoVoList) {
                    if (vo.getId().equals(studentInfo.getProjectCollectInfoId())) {
                        vo.setValue(studentInfo.getValue());
                    }
                }
            }
        }
        if (studentInfos != null) {
            return ApiResponse.builder().code(Constant.RESPONSE_CODE_SUCCESS).data(collectInfoVoList).build();
        } else {
            return ApiResponse.builder().code(Constant.RESPONSE_CODE_31010136).data(collectInfoVoList).build();
        }
    }

    @SneakyThrows
    @Override
    public ApiResponse<Object> queryStudentBaseInfo(String studentId, String projectId) {
        List<StudentInfoVo> list = getByStudentId(projectId, studentId);
        List<ProjectCollectInfoVo> collectInfoVoList = iProjectCollectInfoService.queryByProjectId(projectId);
        String birthdayId = StringUtils.EMPTY;
        for (int i = 0; i < collectInfoVoList.size(); i++) {
            if (ComponentNameEnum.birthday.getCode().equals(collectInfoVoList.get(i).getComponentName())) {
                birthdayId = collectInfoVoList.get(i).getId();
            }
        }
        if (CollectionUtils.isNotEmpty(list)) {
            for (StudentInfoVo studentInfo : list) {
                // 这里是日期的格式保留年月日
                if (birthdayId.equals(studentInfo.getProjectCollectInfoId())) {
                    if (StringUtils.isNotBlank(studentInfo.getValue())) {
                        if (studentInfo.getValue().length() > 10) {
                            studentInfo.setValue(studentInfo.getValue().substring(0, 10));
                        } else {
                            studentInfo.setValue(studentInfo.getValue());
                        }
                    }
                }
            }
        }
        if (list != null) {
            return ApiResponse.builder().code(Constant.RESPONSE_CODE_SUCCESS).data(list).build();
        } else {
            return ApiResponse.builder().code(Constant.RESPONSE_CODE_31010136).data(list).build();
        }
    }

    @Override
    public ApiResponse<Object> updateStudentInfoData(StudentInfoListVo studentInfoListVo) {
        // 校验项目信息是不是存在
        String projectId = studentInfoListVo.getProjectId();
        if (StrUtil.isEmptyIfStr(projectId)) {
            return ApiResponse.builder().code(31111101).data("报名项目信息不存在！").build();
        }
        Project project = iProjectService.getById(projectId);
        if (null == project) {
            return ApiResponse.builder().code(31111101).data("报名项目信息不存在！").build();
        }
        // 校验是不是已经过了审核时间
        Boolean validateSubmitEndResult = validateAuditEnd(project);
        if (!validateSubmitEndResult) {
            return ApiResponse.builder().code(31081105).data("报名已经截止了，不允许提交考生信息！").build();
        }
        Integer bool = saveOrUpdateStu(project, studentInfoListVo, Constants.PUSH_TYPE_UPDATE);
        return ApiResponse.builder().code(bool).data(null).build();
    }

    @Override
    public ApiResponse<Object> addStudentInfoData(StudentInfoListVo studentInfoListVo) {
        // 校验项目信息是不是存在
        String projectId = studentInfoListVo.getProjectId();
        if (StrUtil.isEmptyIfStr(projectId)) {
            return ApiResponse.builder().code(31111101).data("报名项目信息不存在！").build();
        }
        Project project = iProjectService.getById(projectId);
        if (null == project) {
            return ApiResponse.builder().code(31111101).data("报名项目信息不存在！").build();
        }
        Boolean validateSubmitEndResult = validateSingUpEnd(project);
        if (!validateSubmitEndResult) {
            return ApiResponse.builder().code(31081105).data("报名已经截止了，不允许提交考生信息！").build();
        }

        String studentId = saveList(project, studentInfoListVo.getList(), studentInfoListVo);
        return ApiResponse.builder().code(Constant.RESPONSE_CODE_SUCCESS).data(studentId).build();
    }

    @Override
    public List<StudentInfo> listByStudentId(String projectId, String studentId) {
        return this.lambdaQuery()
                .eq(BaseEntity::getDelFlag, Boolean.FALSE)
                .eq(StudentInfo::getProjectId, projectId)
                .eq(StudentInfo::getStudentId, studentId)
                .list();
    }

    public Boolean validateSingUpEnd(Project project) {
        // 如果是管理员则不受限制
        Boolean isManager = UserTypeEnum.isManager(iBaseLoginService.getSysUser());
        if (isManager) {
            return Boolean.TRUE;
        }
        LocalDateTime endTime = project.getEndTime();
        if (LocalDateTime.now().compareTo(endTime) > 0) {
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    private Boolean validateAuditEnd(Project project) {
        // 如果是管理员则不受限制
        Boolean isManager = UserTypeEnum.isManager(iBaseLoginService.getSysUser());
        if (isManager) {
            return Boolean.TRUE;
        }
        // 如果是考生则受限制到了审核时间不允许修改信息了
        if (BmProjectNeedAuditEnum.NEEDAUDIT.getAuditStatus().equals(project.getIsVerify())) {
            if (null != project.getAuditEndTime() && LocalDateTime.now().compareTo(project.getAuditEndTime()) > 0) {
                return Boolean.FALSE;
            }
            if (null == project.getAuditEndTime() && LocalDateTime.now().compareTo(project.getEndTime()) > 0) {
                return Boolean.FALSE;
            }
        }
        return Boolean.TRUE;
    }

    /**
     * 构造父子级value集合
     *
     * @param value
     * @param optionList
     * @param resultList
     * @return
     */
    private LinkedList<ProjectCollectInfoOption> buildValue(String value, List<ProjectCollectInfoOption> optionList, LinkedList<ProjectCollectInfoOption> resultList) {
        for (int i = 0; i < optionList.size(); i++) {
            if (value.equals(optionList.get(i).getOptionValue())) {
                resultList.add(optionList.get(i));
                if (StringUtils.isNotBlank(optionList.get(i).getParentOptionValue())) {
                    resultList = buildValue(optionList.get(i).getParentOptionValue(), optionList, resultList);
                }
            }
        }
        return resultList;
    }

    //同步考生采集信息中的name phone card_type card_number至bm_studnet_projcet表中去
    private void ansycStudentInfo(List<StudentInfo> studentInfos, String projectId, StudentProject studentProject) {
        // 获取考生名字的采集字段
        String nameCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.name.getCode(), projectId, DelFlagEnum.NORMAL.getCode());
        // 获取考生名字的采集值
        Optional<String> nameCollectValueOpt = studentInfos.stream()
                .filter(data -> StrUtil.equals(data.getProjectCollectInfoId(), nameCollectId))
                .map(StudentInfo::getValue)
                .filter(StrUtil::isNotBlank)
                .findAny();
        nameCollectValueOpt.ifPresent(studentProject::setName);

        //获取考生手机号的采集字段
        String phoneCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.phone.getCode(), projectId, DelFlagEnum.NORMAL.getCode());
        // 获取考生手机号的采集值
        Optional<String> phoneCollectValueOpt = studentInfos.stream()
                .filter(data -> StrUtil.equals(data.getProjectCollectInfoId(), phoneCollectId))
                .map(StudentInfo::getValue)
                .filter(StrUtil::isNotBlank)
                .findAny();
        phoneCollectValueOpt.ifPresent(studentProject::setPhone);

        //获取考生证件类型采集字段
        String cardTypeCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.certificatetype.getCode(), projectId, DelFlagEnum.NORMAL.getCode());
        // 获取考生证件类型的采集值
        Optional<String> cardTypeCollectValueOpt = studentInfos.stream()
                .filter(data -> StrUtil.equals(data.getProjectCollectInfoId(), cardTypeCollectId))
                .map(StudentInfo::getValue)
                .filter(StrUtil::isNotBlank)
                .findAny();
        cardTypeCollectValueOpt.ifPresent(studentProject::setCardType);

        //获取考生证件号采集字段
        String cardNumberCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.idcard.getCode(), projectId, DelFlagEnum.NORMAL.getCode());
        // 获取考生证件号的采集值
        Optional<String> cardNumberCollectValueOpt = studentInfos.stream()
                .filter(data -> StrUtil.equals(data.getProjectCollectInfoId(), cardNumberCollectId))
                .map(StudentInfo::getValue)
                .filter(StrUtil::isNotBlank)
                .findAny();
        cardNumberCollectValueOpt.ifPresent(studentProject::setCardNumber);
        //获取机构采集字段
        String officeCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.office.getCode(), projectId, DelFlagEnum.NORMAL.getCode());
        // 获取考生证件号的采集值
        Optional<String> officeCollectValueOpt = studentInfos.stream()
                .filter(data -> StrUtil.equals(data.getProjectCollectInfoId(), officeCollectId))
                .map(StudentInfo::getValue)
                .map(data -> getLastDeptId(data))
                .filter(StrUtil::isNotBlank)
                .findAny();
        officeCollectValueOpt.ifPresent(studentProject::setDeptId);
    }

    @SneakyThrows
    @Override
    public void batchImportFile(String projectId, String fileUrl, Boolean createFlag, User currentLoginUser) {
        log.info("[集体报名][文件录入] studentinfo add projectId:{}", projectId);

        // 下载文件
        File tempFile = downloadBatchImportFile(fileUrl);
        ProgressManager.updateProgressCurrent(10, "文件下载完成");

        // 按照文件名做科目切分
        String fileName = FileUtil.mainName(fileUrl);
        log.debug("[集体报名][文件录入] 文件名为：{}", fileName);
        // 校验获取报名的科目
        List<ProjectSubject> allsubjectList = projectSubjectMapper.querySubjectList(projectId, null);
        if (CollUtil.isEmpty(allsubjectList)) {
            BusinessLogicException.throwException(31811125, "未查询到当前报名的科目信息");
        }
        log.debug("[集体报名][文件录入] 报名科目为：{}", FastJsonUtil.getBeanToJson(allsubjectList));
        ProgressManager.updateProgressCurrent(15, "科目校验完成");

        // 获取科目名称和科目对象的映射
        Map<String, ProjectSubject> projectSubjectMap = allsubjectList.stream()
                .collect(Collectors.toMap(ProjectSubject::getSubjectName, Function.identity()));
        // 获取文件名中的科目集合
        List<ProjectSubject> subjectListByFileName = getSubjectListByFileName(fileName, allsubjectList);
        log.debug("[集体报名][文件录入] 文件名中的科目集合：{}", FastJsonUtil.getBeanToJson(subjectListByFileName));
        ProgressManager.updateProgressCurrent(16, "科目提取完成");

        // 校验科目数
        Project project = projectMapper.selectById(projectId);
        ProgressManager.updateProgressCurrent(18, "科目数校验完成");

        // title与对应的采集信息数据
        List<ProjectCollectInfoVo> volist = iProjectCollectInfoService.queryBaseCj(projectId);
        Map<String, ProjectCollectInfoVo> titleMappingProjectCollect = volist.stream().collect(Collectors.toMap(ProjectCollectInfo::getTitle, Function.identity()));
        ProgressManager.updateProgressCurrent(20, "采集字段头获取完成");

        // 解析excel文件数据
        ExcelDto excelDto = EasyexcelUtil.getExcelDataList(FileUtil.getInputStream(tempFile));
        ProgressManager.updateProgressCurrent(22, "Excel文件数据解析完成");

        // 校验表格数据
        validateExcelFileData(excelDto, titleMappingProjectCollect, allsubjectList);
        ProgressManager.updateProgressCurrent(24, "表格数据校验完成");

        // 构建数据标识
        ProjectStudentImportRecordParam recordParam = ProjectStudentImportRecordParam.buildParamsFlag(volist);
        if (createFlag && !(recordParam.getPhoneflag() || recordParam.getEmailflag())) {
            BusinessLogicException.throwException(31811112, "需要创建账号，但是文件中缺少电话号码或者邮箱采集数据，请重新导入！", recordParam);
        }
        ProgressManager.updateProgressCurrent(26, "数据标识构建完成");

        // 组装批量导入文件统计
        BatchImportFileStatisticDTO batchImportFileStatisticDTO = assembleStatisticCollect(projectId, excelDto.getRowDataList());
        ProgressManager.updateProgressCurrent(30, "考生采集数据信息统计完成");

        // 报名科目数统计
        Map<String, AtomicInteger> subjectIdMappingCount = this.assembleSubjectCount(allsubjectList);
        // 考生校验数据集合
        List<ImportStudentDataVO> importStudentDataVOList = Lists.newLinkedList();
        // 遍历考生数据
        for (int i = 0; i < excelDto.getRowDataList().size(); i++) {
            Map<String, String> studentInfoMap = CollUtil.get(excelDto.getRowDataList(), i);
            String studentId = UUIDUtils.newSortUUID();
            String studentName = MapUtil.getStr(studentInfoMap, ComponentNameEnum.name.getDesc());
            String cardType = MapUtil.getStr(studentInfoMap, ComponentNameEnum.certificatetype.getDesc());
            String cardNumber = MapUtil.getStr(studentInfoMap, ComponentNameEnum.idcard.getDesc());

            CheckUtil.CheckHandler checkHandler = CheckUtil.none();
            // 校验基础数据
            validateBaseCommonData(checkHandler, cardType, cardNumber, batchImportFileStatisticDTO);
            // 校验和装配科目表头
            List<String> subjectTitleNameData = validateAndAssembleSubjectTitleData(checkHandler, allsubjectList, studentInfoMap);
            // 获取考生对应报名的科目
            Set<ProjectSubject> studentProjectSubjectList = getStudentProjectSubjectList(subjectTitleNameData, projectSubjectMap, subjectListByFileName, allsubjectList);

            // 创建考生的科目集合
            List<StudentSubject> importStudentSubjects = studentProjectSubjectList.stream()
                    .map(studentProjectSubject -> createStudentSubject(projectId, studentProjectSubject, studentId, currentLoginUser.getId()))
                    .collect(Collectors.toList());
            // 校验科目数据、是否有报名资格
            validateSubjectData(checkHandler, importStudentSubjects, subjectIdMappingCount, project, studentProjectSubjectList, cardNumber);

            // 校验和装配考生采集信息集合
            List<StudentInfo> studentInfoList = assembleStudentInfoList(titleMappingProjectCollect, studentInfoMap, checkHandler, batchImportFileStatisticDTO, projectId, currentLoginUser, studentId);

            // 创建考生报名信息
            StudentProject studentProject = assembleStudentProject(studentId, projectId, studentInfoList, currentLoginUser, volist);

            ImportStudentDataVO importStudentDataVO = ImportStudentDataVO.builder()
                    .studentName(studentName)
                    .identificationNo(cardNumber)
                    .studentInfoData(studentInfoMap)
                    .studentProject(studentProject)
                    .studentSubject(importStudentSubjects)
                    .studentInfo(studentInfoList)
                    .validStatus(checkHandler.hasException())
                    .validMessage(checkHandler.allMessageCollect())
                    .errorCodes(checkHandler.allExceptionCodeCollect())
                    .build();
            importStudentDataVOList.add(importStudentDataVO);

            String resultMessage = StrUtil.format("{}项目第{}条数据，考生名称{}校验完成", project.getProjectName(), i + 1, studentName);
            ProgressManager.stepProgressCurrent(i, excelDto.getRowDataList().size(), 35, 90, resultMessage);
        }

        Optional<Boolean> validStatus = importStudentDataVOList.stream()
                .map(ImportStudentDataVO::getValidStatus)
                .distinct()
                .filter(data -> data)
                .findAny();
        ProgressManager.updateProgressCurrent(92, "导入失败数据提取完成");

        // 不为空则说明有错误
        if (validStatus.isPresent()) {
            String failDataExcelUrl = assembleFailExcelUrl(importStudentDataVOList, project.getProjectName());
            BatchSaveImportDataVO batchSaveImportDataVO = BatchSaveImportDataVO.builder()
                    .validFail(Boolean.TRUE)
                    .failExcelUrl(failDataExcelUrl)
                    .build();
            ProgressManager.finish(batchSaveImportDataVO);
            return;
        }

        // 批量保存导入数据并且创建账号
        iStudentProject.batchSaveImportData(projectId, importStudentDataVOList, recordParam, createFlag, currentLoginUser);
        BatchSaveImportDataVO batchSaveImportDataVO = BatchSaveImportDataVO.builder()
                .validFail(Boolean.FALSE)
                .build();
        ProgressManager.finish(batchSaveImportDataVO);
    }

    /**
     * 报名科目数统计
     *
     * @param allsubjectList
     * @return
     */
    private Map<String, AtomicInteger> assembleSubjectCount(List<ProjectSubject> allsubjectList) {
        Map<String, AtomicInteger> dbSubjectCount = allsubjectList.stream()
                .collect(Collectors.toMap(ProjectSubject::getSubjectId, projectSubject -> {
                    // 获取库中已报名数
                    Integer dbStudentCount = iStudentSubjectService.countBySubjectId(projectSubject.getProjectId(), projectSubject.getSubjectId());
                    return new AtomicInteger(dbStudentCount);
                }));

        return dbSubjectCount;
    }

    /**
     * 校验和装配科目表头
     *
     * @param checkHandler
     * @param allsubjectList
     * @param studentInfoMap
     * @return
     */
    private List<String> validateAndAssembleSubjectTitleData(CheckUtil.CheckHandler checkHandler, List<ProjectSubject> allsubjectList, Map<String, String> studentInfoMap) {
        List<String> subjectNames = allsubjectList.stream()
                .map(ProjectSubject::getSubjectName)
                .collect(Collectors.toList());

        for (String subjectName : subjectNames) {
            String selectValue = MapUtil.getStr(studentInfoMap, subjectName);
            String formatMessage = StrUtil.format("科目”{}“未选择", subjectName);
            checkHandler.collect(selectValue, StrRuler.notBlank(31811128, formatMessage));
        }

        List<String> selectedSubjectNames = subjectNames.stream()
                .filter(data -> {
                    String selectValue = MapUtil.getStr(studentInfoMap, data);
                    return StrUtil.equals(selectValue, IMPORT_YES);
                }).collect(Collectors.toList());

        return selectedSubjectNames;
    }

    @SneakyThrows
    @Override
    public String batchImportTemplate(String projectId) {
        if (StrUtil.isBlank(projectId)) {
            BusinessLogicException.throwException(31082302, "报名项目不能为空");
        }
        Project project = iProjectService.getProjectById(projectId);

        List<ProjectSubject> projectSubjects = iProjectSubjectService.getProjectSubjectsByProjectId(projectId);
        if (CollUtil.isEmpty(projectSubjects)) {
            BusinessLogicException.throwException(31082303, "报名项目未查询到科目数据");
        }
        for (ProjectSubject projectSubject : projectSubjects) {
            if (StrUtil.isBlank(projectSubject.getSubjectName())) {
                BusinessLogicException.throwException(31082304, "报名项目未查询到科目数据");
            }
        }

        List<ProjectCollectInfoVo> projectCollectInfoVos = iProjectCollectInfoService.queryBaseCj(projectId);
        List<BatchImportTemplateDTO> formFieldKeyValuePairs = projectCollectInfoVos.stream()
                .map(data -> {
                    // 获取下拉选项值
                    String[] optionStr = Opt.ofNullable(data.getOptionList())
                            .filter(CollUtil::isNotEmpty)
                            .stream()
                            .flatMap(Collection::stream)
                            .map(ProjectCollectInfoOption::getOptionLabel)
                            .filter(StrUtil::isNotBlank)
                            .distinct()
                            .toArray(String[]::new);

                    // 地区不设置下拉
                    if (StrUtil.equals(data.getComponentName(), ComponentNameEnum.area.getCode())) {
                        optionStr = null;
                    }
                    return new BatchImportTemplateDTO(data.getTitle(), optionStr);
                }).collect(Collectors.toList());

        // 设置科目下拉
        List<BatchImportTemplateDTO> subjectOptions = projectSubjects.stream()
                .map(data -> new BatchImportTemplateDTO(data.getSubjectName(), SUBJECT_TEMPLATE_OPTIONS))
                .collect(Collectors.toList());
        CollUtil.addAll(formFieldKeyValuePairs, subjectOptions);
        SXSSFWorkbook workbook =  new SXSSFWorkbook(100);
        String fileUrl = "";
        try{
            Sheet sheet = workbook.createSheet(project.getProjectName());
            Row titleNameRow = sheet.createRow(CommonConstant.ZERO);
            for (int i = 0; i < formFieldKeyValuePairs.size(); i++) {
                BatchImportTemplateDTO formFieldKeyValuePair = CollUtil.get(formFieldKeyValuePairs, i);
                // 写入excel的表头
                Cell cell = titleNameRow.createCell(i);
                cell.setCellValue(formFieldKeyValuePair.getTitle());
                // 设置宽度
                sheet.setColumnWidth(i, ExcelExportUtil.DEFAULT_TABLE_CELL_WIDTH * 256);
                // 设置单元格下拉
                String[] options = formFieldKeyValuePair.getOptions();
                if (ArrayUtil.isNotEmpty(options)) {
                    DataValidationHelper helper = sheet.getDataValidationHelper();
                    DataValidationConstraint constraint = helper.createExplicitListConstraint(options);
                    CellRangeAddressList regions = new CellRangeAddressList(CommonConstant.ONE, 65534, i, i);
                    DataValidation dataValidation = helper.createValidation(constraint, regions);
                    sheet.addValidationData(dataValidation);
                }
            }

            File tempFile = FileUtil.createTempFile(XLSX_FILE_SUFFIX, Boolean.TRUE);
            try (BufferedOutputStream bufferedOutputStream = FileUtil.getOutputStream(tempFile)) {
                workbook.write(bufferedOutputStream);
                IoUtil.flush(bufferedOutputStream);
            }

            String lastFileName = StrUtil.format("集体报名模板_{}_{}{}", project.getProjectName(), System.currentTimeMillis(), XLSX_FILE_SUFFIX);
            fileUrl = uploadFileToHuaweiUtil.uploadFileToHuawei(tempFile, XLSX_FILE_TYPE, lastFileName);
        } catch (Exception ex){
            logger.error("创建excel表格失败");
        } finally {
            if(workbook != null){
                workbook.close();
            }
        }
        return fileUrl;
    }

    /**
     * 创建考生报名信息
     *
     * @param projectId
     * @param studentInfoList
     * @param currentLoginUser
     * @param volist
     * @return
     */
    private StudentProject assembleStudentProject(String studentId, String projectId, List<StudentInfo> studentInfoList, User currentLoginUser, List<ProjectCollectInfoVo> volist) {
        // Map<ProjectCollectInfoId, ComponentName> 获取采集字段名称和采集字段ID的映射
        Map<String, String> collectInfoIdMappingCode = volist.stream()
                .collect(Collectors.toMap(ProjectCollectInfoVo::getId, ProjectCollectInfoVo::getComponentName));
        // Map<ComponentName, Value>获取采集字段名称和采集字段值的映射
        Map<String, Opt<String>> codeMappingValue = studentInfoList.stream()
                .map(data -> {
                    String code = MapUtil.getStr(collectInfoIdMappingCode, data.getProjectCollectInfoId());
                    return MapUtil.<String, Opt<String>>builder()
                            .put(code, Opt.ofNullable(data.getValue()))
                            .build();
                }).map(Map::entrySet)
                .flatMap(Collection::stream)
                .filter(data -> StrUtil.isNotBlank(data.getKey()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (existing, replacement) -> existing));

        LocalDateTime now = LocalDateTime.now();
        StudentProject studentProject = new StudentProject();
        studentProject.setIsAudit(BmAuditStatusEnum.APPROVED.getAuditStatus());
        studentProject.setId(studentId);
        studentProject.setProjectId(projectId);
        studentProject.setOfficeId(currentLoginUser.getOfficeid());
        studentProject.setDeptId(currentLoginUser.getOrganizationid());
        studentProject.setCreateDate(now);
        studentProject.setUpdateDate(now);
        studentProject.setCreateBy(currentLoginUser.getId());
        studentProject.setUpdateBy(currentLoginUser.getId());

        TypeReference<Opt<String>> typeReference = new TypeReference<Opt<String>>() {
        };
        MapUtil.get(codeMappingValue, ComponentNameEnum.name.getCode(), typeReference, Opt.empty())
                .ifPresent(studentProject::setName);
        MapUtil.get(codeMappingValue, ComponentNameEnum.certificatetype.getCode(), typeReference, Opt.empty())
                .ifPresent(studentProject::setCardType);
        MapUtil.get(codeMappingValue, ComponentNameEnum.idcard.getCode(), typeReference, Opt.empty())
                .ifPresent(studentProject::setCardNumber);
        MapUtil.get(codeMappingValue, ComponentNameEnum.office.getCode(), typeReference, Opt.empty())
                .map(data -> StrUtil.split(data, StrUtil.COMMA))
                .map(CollUtil::getLast)
                .filter(StrUtil::isNotBlank)
                .ifPresent(studentProject::setDeptId);
        MapUtil.get(codeMappingValue, ComponentNameEnum.phone.getCode(), typeReference, Opt.empty())
                .ifPresent(studentProject::setPhone);
        return studentProject;
    }

    /**
     * 考生采集信息集合
     *
     * @param titleMappingProjectCollect
     * @param studentInfoMap
     * @param checkHandler
     * @param batchImportFileStatisticDTO
     * @param projectId
     * @param currentLoginUser
     * @param studentId
     * @return
     */
    private List<StudentInfo> assembleStudentInfoList(Map<String, ProjectCollectInfoVo> titleMappingProjectCollect,
                                                      Map<String, String> studentInfoMap,
                                                      CheckUtil.CheckHandler checkHandler,
                                                      BatchImportFileStatisticDTO batchImportFileStatisticDTO,
                                                      String projectId,
                                                      User currentLoginUser,
                                                      String studentId) {
        List<StudentInfo> studentInfoList = Lists.newLinkedList();
        // 装配考生信息
        for (Map.Entry<String, ProjectCollectInfoVo> projectCollectInfoVoEntry : titleMappingProjectCollect.entrySet()) {
            String studentCollectName = projectCollectInfoVoEntry.getKey();
            ProjectCollectInfoVo projectCollectInfoVo = projectCollectInfoVoEntry.getValue();
            String studentCollectInfoValue = MapUtil.getStr(studentInfoMap, studentCollectName);

            // 如果当前采集字段是非必须的
            if (projectCollectInfoVo.getRequired() == CommonConstant.ZERO) {
                if (StrUtil.isBlank(studentCollectInfoValue)) {
                    continue;
                }
            }

            // 装配和验证数据格式
            String realValue = assembleAndValidateDataFormat(studentCollectInfoValue, projectCollectInfoVo, checkHandler, batchImportFileStatisticDTO);
            // 组装考生信息
            StudentInfo info = assembleStudentInfoData(realValue, projectCollectInfoVo, studentId, projectId, currentLoginUser);
            studentInfoList.add(info);
        }
        return studentInfoList;
    }

    /**
     * 装配失败Excel数据url
     *
     * @param importStudentDataVOList
     * @param projectName
     * @return
     */
    private String assembleFailExcelUrl(List<ImportStudentDataVO> importStudentDataVOList, String projectName) {
        // 导出考生失败信息
        File tempFailFile = FileUtil.createTempFile(".xlsx", Boolean.TRUE);
        // 文件名称
        String failFileName = StrUtil.format("{}_导入校验失败考生数据_{}.xlsx", projectName, System.currentTimeMillis());
        // 这里 需要指定写用哪个class去写，然后写到第一个sheet，名字为模板 然后文件流会自动关闭
        // 如果这里想使用03 则 传入excelType参数即可
        EasyExcel.write(tempFailFile, ImportStudentDataVO.class)
                .sheet("校验失败数据")
                .doWrite(importStudentDataVOList);
        ProgressManager.updateProgressCurrent(94, "考生失败数据写入Excel完成");

        String failDataExcelUrl = uploadFileToHuaweiUtil.uploadFileToHuawei(tempFailFile, "excel", failFileName);
        return failDataExcelUrl;
    }

    /**
     * 组装批量导入文件统计
     *
     * @param rowDataList
     * @return
     */
    private BatchImportFileStatisticDTO assembleStatisticCollect(String projectId, List<Map<String, String>> rowDataList) {
        BatchImportFileStatisticDTO.BatchImportFileStatisticDTOBuilder batchImportFileStatisticDTOBuilder = BatchImportFileStatisticDTO.builder();
        // 查询报名的采集信息列
        String columns = projectSubjectMapper.getBaseCjSqlColumn(projectId);
        if (StrUtil.isNotBlank(columns)) {
            // 查询库中的考生信息
            List<Map<String, Object>> listMaps = projectSubjectMapper.queryAllStudent(columns, projectId, null, null, null);
            // 获取库中手机号码统计
            Map<String, Long> phoneAccessCount = listMaps.stream()
                    .map(rowData -> MapUtil.getStr(rowData, ComponentNameEnum.phone.getDesc()))
                    .filter(StrUtil::isNotBlank)
                    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
            // 获取库中邮箱统计
            Map<String, Long> emailAccessCount = listMaps.stream()
                    .map(rowData -> MapUtil.getStr(rowData, ComponentNameEnum.email.getDesc()))
                    .filter(StrUtil::isNotBlank)
                    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
            // 获取库中准考证号统计
            Map<String, Long> admissionNoAccessCount = listMaps.stream()
                    .map(rowData -> MapUtil.getStr(rowData, ComponentNameEnum.admissionno.getDesc()))
                    .filter(StrUtil::isNotBlank)
                    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
            // 获取库中身份证号统计
            Map<String, Long> idCardAccessCount = listMaps.stream()
                    .map(rowData -> MapUtil.getStr(rowData, ComponentNameEnum.idcard.getDesc()))
                    .filter(StrUtil::isNotBlank)
                    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

            batchImportFileStatisticDTOBuilder
                    .admissionNoAccessCount(admissionNoAccessCount)
                    .emailAccessCount(emailAccessCount)
                    .idCardAccessCount(idCardAccessCount)
                    .phoneAccessCount(phoneAccessCount);
        }

        // 获取手机号码统计
        Map<String, Long> phoneMappingCount = rowDataList.stream()
                .map(rowData -> MapUtil.getStr(rowData, ComponentNameEnum.phone.getDesc()))
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
        // 获取邮箱统计
        Map<String, Long> emailMappingCount = rowDataList.stream()
                .map(rowData -> MapUtil.getStr(rowData, ComponentNameEnum.email.getDesc()))
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
        // 获取准考证号统计
        Map<String, Long> admissionNoMappingCount = rowDataList.stream()
                .map(rowData -> MapUtil.getStr(rowData, ComponentNameEnum.admissionno.getDesc()))
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
        // 获取身份证号统计
        Map<String, Long> idCardMappingCount = rowDataList.stream()
                .map(rowData -> MapUtil.getStr(rowData, ComponentNameEnum.idcard.getDesc()))
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

        BatchImportFileStatisticDTO batchImportFileStatisticDTO = batchImportFileStatisticDTOBuilder
                .admissionNoMappingCount(admissionNoMappingCount)
                .emailMappingCount(emailMappingCount)
                .idCardMappingCount(idCardMappingCount)
                .phoneMappingCount(phoneMappingCount)
                .build();
        return batchImportFileStatisticDTO;
    }

    /**
     * 组装考生信息
     *
     * @param realValue
     * @param projectCollectInfoVo
     * @param studentId
     * @param projectId
     * @param currentLoginUser
     * @return
     */
    private StudentInfo assembleStudentInfoData(String realValue, ProjectCollectInfoVo projectCollectInfoVo, String studentId, String projectId, User currentLoginUser) {
        // 创建考生采集信息对象
        StudentInfo info = new StudentInfo();
        info.setId(UUIDUtils.newSortUUID());
        info.setValue(realValue);
        // 校验和装配数据格式
        info.setProjectCollectInfoId(projectCollectInfoVo.getId());
        info.setStudentId(studentId);
        info.setProjectCollectInfoName(projectCollectInfoVo.getTitle());
        info.setProjectId(projectId);
        info.setCreateBy(currentLoginUser.getId());
        info.setUpdateBy(currentLoginUser.getId());
        return info;
    }

    /**
     * 获取考生报名科目集合
     *
     * @param projectSubjectMap
     * @param subjectListByFileName
     * @param allsubjectList
     * @return
     */
    private Set<ProjectSubject> getStudentProjectSubjectList(List<String> subjectTitleNameData, Map<String, ProjectSubject> projectSubjectMap, List<ProjectSubject> subjectListByFileName, List<ProjectSubject> allsubjectList) {
        // 校验科目
        if (CollUtil.isNotEmpty(subjectTitleNameData)) {
            // 科目是否不完整
            Set<ProjectSubject> studentCollectSubject = subjectTitleNameData.stream()
                    .map(subjectNameTx -> MapUtil.get(projectSubjectMap, subjectNameTx, ProjectSubject.class))
                    .filter(ObjectUtil::isNotEmpty)
                    .collect(Collectors.toSet());
            // 合并文件名称的科目
            CollUtil.addAll(studentCollectSubject, subjectListByFileName);
            return studentCollectSubject;
        } else if (CollUtil.isNotEmpty(subjectListByFileName)) {
            // 如果科目不为空则用导入的科目,合并到主科目上
            return Sets.newHashSet(subjectListByFileName);
        } else {
            // 如果文件科目为空、导入科目也为空就用返回空集合
            return Sets.newHashSet();
        }
    }

    /**
     * 校验科目数据
     *
     * @param checkHandler
     * @param importStudentSubjects
     * @param subjectIdMappingCount
     * @param project
     * @param studentProjectSubjectList
     * @param cardNumber
     */
    private void validateSubjectData(CheckUtil.CheckHandler checkHandler,
                                     List<StudentSubject> importStudentSubjects,
                                     Map<String, AtomicInteger> subjectIdMappingCount,
                                     Project project,
                                     Set<ProjectSubject> studentProjectSubjectList,
                                     String cardNumber) {
        // 将科目报名总数进行自增
        importStudentSubjects.stream()
                .map(StudentSubject::getSubjectId)
                .forEach(subjectId -> {
                    AtomicInteger atomicInteger = MapUtil.computeIfAbsent(subjectIdMappingCount, subjectId, data -> new AtomicInteger());
                    atomicInteger.incrementAndGet();
                });

        // 当前报名是否为非开放报名
        List<String> nonOpenSubjectIds = Lists.newArrayList();
        if (project.getIsOpen() == CommonConstant.ZERO) {
            if (StrUtil.isNotBlank(cardNumber)) {
                NonOpenInfo nonOpenInfo = iNonOpenService.queryStudentByCardNum(project.getId(), cardNumber);
                // 科目是否限制了报名指定科目
                checkHandler.collect(nonOpenInfo, checkTarget -> {
                    if (nonOpenInfo == null) {
                        throw new CheckException(31811130, "当前考生没有报考资格");
                    }
                });
                if (nonOpenInfo != null) {
                    String subjectIds = nonOpenInfo.getSubjectIds();
                    List<String> subjectIdList = StrUtil.split(subjectIds, StrUtil.COMMA);
                    CollUtil.addAll(nonOpenSubjectIds, subjectIdList);
                }
            }
        }

        if (CollUtil.isNotEmpty(nonOpenSubjectIds)) {
            // 科目是否限制了报名指定科目
            checkHandler.collect(nonOpenSubjectIds, checkTarget -> {
                if (CollUtil.size(nonOpenSubjectIds) < CollUtil.size(studentProjectSubjectList)) {
                    throw new CheckException(31811132, "选择的报考科目与设置的报名可选科目不匹配");
                }
            });
        }


        for (ProjectSubject projectSubject : studentProjectSubjectList) {
            // 如果当前报名的科目限制最大科目报名数
            if (projectSubject.getLimitSubjectRegister() == CommonConstant.ONE) {
                // 验证最大报名数
                checkHandler.collect(projectSubject, checkTarget -> {
                    AtomicInteger subjectCountAtomic = MapUtil.get(subjectIdMappingCount, checkTarget.getSubjectId(), AtomicInteger.class);
                    if (subjectCountAtomic.get() > checkTarget.getMaxNumberofRegister()) {
                        String checkMessage = StrUtil.format("当前报名科目“{}”超出科目人数“{}”人限制", checkTarget.getSubjectName(), checkTarget.getMaxNumberofRegister());
                        throw new CheckException(31811127, checkMessage);
                    }
                });
            }

            // 当前报名是否为非开放报名
            if (project.getIsOpen() == CommonConstant.ZERO) {
                checkHandler.collect(nonOpenSubjectIds, checkTarget -> {
                    boolean contains = CollUtil.contains(nonOpenSubjectIds, projectSubject.getSubjectId());
                    if (!contains) {
                        String checkMessage = StrUtil.format("当前考生没有报考科目“{}”的资格", projectSubject.getSubjectName());
                        throw new CheckException(31811131, checkMessage);
                    }
                });
            }
        }

        checkHandler.collect(studentProjectSubjectList, checkTarget -> {
            if (CollUtil.size(checkTarget) > project.getMaxSubject()) {
                throw new CheckException(31811126, "选择的报考科目数量不能大于设置的最多可报考科目数量");
            }
        });

        checkHandler.collect(studentProjectSubjectList, checkTarget -> {
            if (CollUtil.size(checkTarget) < project.getMinSubject()) {
                throw new CheckException(31811129, "选择的报考科目数量不能小于设置的最少可报考科目数量");
            }
        });
    }

    /**
     * 校验基础数据
     *
     * @param checkHandler
     * @param cardType
     * @param cardNumber
     */
    private void validateBaseCommonData(CheckUtil.CheckHandler checkHandler,
                                        String cardType,
                                        String cardNumber,
                                        BatchImportFileStatisticDTO batchImportFileStatisticDTO) {
        // 校验证件类型
        if (StrUtil.isNotBlank(cardType)) {
            checkHandler.collect(cardType, "证件类型", StrRuler.notBlank(), IdCardRuler.typeCheck());
        } else {
            // 校验证件类型转换
            IdCardTypeEnum idCardTypeEnum = IdCardTypeEnum.getByKeyword(cardType);
            checkHandler.collect(cardType, checkTarget -> {
                if (ObjectUtil.equals(idCardTypeEnum, IdCardTypeEnum.NONE)) {
                    throw new CheckException(31213105, "不支持的证件类型");
                }
            });

            // 只校验大陆居民身份证号码的有效性
            if (ObjectUtil.equals(IdCardTypeEnum.CHINA, idCardTypeEnum)) {
                // 校验证件有效性
                checkHandler.collect(cardNumber, checkTarget -> {
                    if (IdcardUtil.isValidCard(checkTarget)) {
                        return;
                    }
                    throw new CheckException(31213106, "证件号码校验不通过");
                });
            }
        }

        // 校验证件号码
        if (StrUtil.isBlank(cardNumber)) {
            checkHandler.collect(cardNumber, "证件号码", StrRuler.notBlank());
        } else {
            // 证件文件中是否重复
            checkHandler.collect(cardNumber, checkTarget -> {
                Long numberCount = MapUtil.getLong(batchImportFileStatisticDTO.getIdCardMappingCount(), checkTarget, CommonConstant.ROOT_ID);
                if (numberCount > CommonConstant.ONE) {
                    throw new CheckException(31213108, "导入文件中证件号码重复");
                }
            });

            // 证件库中是否重复
            checkHandler.collect(cardNumber, checkTarget -> {
                Long numberCount = MapUtil.getLong(batchImportFileStatisticDTO.getIdCardAccessCount(), checkTarget, CommonConstant.ROOT_ID);
                if (numberCount >= CommonConstant.ONE) {
                    throw new CheckException(31213108, "数据库中证件号码重复");
                }
            });
        }
    }

    /**
     * 校验表数据
     *
     * @return
     */
    private void validateExcelFileData(ExcelDto excelDto, Map<String, ProjectCollectInfoVo> titleMappingProjectCollect, List<ProjectSubject> allsubjectList) {
        // 校验表数据
        if (CollectionUtils.isEmpty(excelDto.getRowDataList())) {
            throw new InvalidRequestException(31811116, "解析导入数据表内容为空，请完整内容重新导入！");
        }
        log.debug("[集体报名][文件录入] 解析出Excel表数据{}条", CollUtil.size(excelDto.getRowDataList()));

        if (CollUtil.isEmpty(excelDto.getHeadMap())) {
            BusinessLogicException.throwException(31811121, "未解析出表头数据，请重新导入");
        }
        log.debug("[集体报名][文件录入] 解析出Excel表头为：{}", FastJsonUtil.getBeanToJson(excelDto.getHeadMap()));

        // 校验表头是否重复
        Map<String, Long> titleMappingCount = excelDto.getHeadMap().values()
                .stream()
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
        for (Map.Entry<String, Long> titleEntry : titleMappingCount.entrySet()) {
            if (titleEntry.getValue() > CommonConstant.ONE) {
                String formatMessage = StrUtil.format("表头“{}”重复，请修改后重新导入", titleEntry.getKey());
                BusinessLogicException.throwException(ProgressConstant.RESPONSE_CODE_BUSINESS_ERROR, formatMessage, titleEntry);
            }
        }

        for (Map.Entry<String, ProjectCollectInfoVo> projectCollectInfoVoEntry : titleMappingProjectCollect.entrySet()) {
            String collectTitle = projectCollectInfoVoEntry.getKey();
            boolean titleContains = CollUtil.contains(excelDto.getHeadMap().values(), collectTitle);
            if (!titleContains) {
                String formatMessage = StrUtil.format("表头未解析出指定采集字段“{}”", collectTitle);
                BusinessLogicException.throwException(ProgressConstant.RESPONSE_CODE_BUSINESS_ERROR, formatMessage);
            }
        }

        for (ProjectSubject projectSubject : allsubjectList) {
            String subjectName = projectSubject.getSubjectName();
            boolean titleContains = CollUtil.contains(excelDto.getHeadMap().values(), subjectName);
            if (!titleContains) {
                String formatMessage = StrUtil.format("表头未解析出指定科目名称字段“{}”", subjectName);
                BusinessLogicException.throwException(ProgressConstant.RESPONSE_CODE_BUSINESS_ERROR, formatMessage);
            }
        }
    }

    /**
     * 下载文件
     *
     * @param fileUrl
     * @return
     */
    private File downloadBatchImportFile(String fileUrl) {
        File tempFile = FileUtil.createTempFile(".xlsx", Boolean.TRUE);
        HttpUtil.downloadFile(fileUrl, tempFile, 60 * 1000);
        if (tempFile.length() == CommonConstant.ZERO) {
            BusinessLogicException.throwException(31082202, "上传的文件为空");
        }
        return tempFile;
    }


    /**
     * 创建考生科目
     *
     * @param projectId
     * @param userId
     * @return
     */
    private static StudentSubject createStudentSubject(String projectId, ProjectSubject projectSubject, String studentId, String userId) {
        LocalDateTime now = LocalDateTime.now();
        StudentSubject studentSubject = new StudentSubject();
        studentSubject.setSubjectId(projectSubject.getSubjectId());
        studentSubject.setStudentId(studentId);
        studentSubject.setSubjectName(projectSubject.getSubjectName());
        studentSubject.setProjectId(projectId);
        studentSubject.setPay(CommonConstant.ZERO);
        studentSubject.setIsPay(projectSubject.getIsPay());
        studentSubject.setIsAudit(BmAuditStatusEnum.APPROVED.getAuditStatus());
        studentSubject.setCreateDate(now);
        studentSubject.setUpdateDate(now);
        studentSubject.setCreateBy(userId);
        studentSubject.setUpdateBy(userId);
        return studentSubject;
    }

    /**
     * 装配和验证数据格式
     *
     * @param studentValue
     * @param projectCollectInfoVo
     */
    private String assembleAndValidateDataFormat(String studentValue,
                                                 ProjectCollectInfoVo projectCollectInfoVo,
                                                 CheckUtil.CheckHandler checkHandler,
                                                 BatchImportFileStatisticDTO batchImportFileStatisticDTO) {
        if (StrUtil.isBlank(studentValue)) {
            checkHandler.collect(studentValue, projectCollectInfoVo.getTitle(), StrRuler.notBlank());
            return studentValue;
        }

        // 如果是下拉框，则校验下拉框的值是否存在
        List<ProjectCollectInfoOption> projectCollectInfoVoOptionList = projectCollectInfoVo.getOptionList();
        if (CollectionUtils.isNotEmpty(projectCollectInfoVoOptionList)) {
            ProjectCollectInfoOption projectCollectInfoOption = null;
            for (ProjectCollectInfoOption collectInfoOption : projectCollectInfoVoOptionList) {
                if (studentValue.equals(collectInfoOption.getOptionLabel())) {
                    projectCollectInfoOption = collectInfoOption;
                    studentValue = projectCollectInfoOption.getOptionValue();
                }
            }
            if (null == projectCollectInfoOption) {
                String exceptionMessage = StrUtil.format("文件采集内容<{}>与{}采集信息定义不一致", studentValue, projectCollectInfoVo.getTitle());
                checkHandler.collect(projectCollectInfoOption, checkTarget -> {
                    if (null == checkTarget) {
                        throw new CheckException(31811123, exceptionMessage);
                    }
                });
            } else {
                // 做层级数据补齐
                studentValue = getOptionsLevelValue(studentValue, projectCollectInfoOption, projectCollectInfoVoOptionList);
            }
        }

        Optional<ComponentNameEnum> componentNameEnumOpt = Arrays.stream(ComponentNameEnum.values())
                .filter(data -> StrUtil.equals(data.getDesc(), projectCollectInfoVo.getTitle()))
                .findAny();

        if (componentNameEnumOpt.isPresent()) {
            ComponentNameEnum componentNameEnum = componentNameEnumOpt.get();
            switch (componentNameEnum) {
                case phone:
                    // 文件中手机是否重复
                    checkHandler.collect(studentValue, checkTarget -> {
                        Long numberCount = MapUtil.getLong(batchImportFileStatisticDTO.getPhoneMappingCount(), checkTarget, CommonConstant.ROOT_ID);
                        if (numberCount > CommonConstant.ONE) {
                            throw new CheckException(31213108, "导入文件中手机号码重复");
                        }
                    });

                    // 库中手机号码是否重复
                    checkHandler.collect(studentValue, checkTarget -> {
                        Long numberCount = MapUtil.getLong(batchImportFileStatisticDTO.getPhoneAccessCount(), checkTarget, CommonConstant.ROOT_ID);
                        if (numberCount >= CommonConstant.ONE) {
                            throw new CheckException(31213108, "数据库中手机号码重复");
                        }
                    });
                    break;
                case email:
                    // 文件中邮件是否重复
                    checkHandler.collect(studentValue, checkTarget -> {
                        Long numberCount = MapUtil.getLong(batchImportFileStatisticDTO.getEmailMappingCount(), checkTarget, CommonConstant.ROOT_ID);
                        if (numberCount > CommonConstant.ONE) {
                            throw new CheckException(31213108, "导入文件中邮件重复");
                        }
                    });

                    // 证件库中是否重复
                    checkHandler.collect(studentValue, checkTarget -> {
                        Long numberCount = MapUtil.getLong(batchImportFileStatisticDTO.getEmailAccessCount(), checkTarget, CommonConstant.ROOT_ID);
                        if (numberCount >= CommonConstant.ONE) {
                            throw new CheckException(31213108, "数据库中邮件重复");
                        }
                    });
                    break;
                case admissionno:
                    // 文件中准考证号是否重复
                    checkHandler.collect(studentValue, checkTarget -> {
                        Long numberCount = MapUtil.getLong(batchImportFileStatisticDTO.getAdmissionNoMappingCount(), checkTarget, CommonConstant.ROOT_ID);
                        if (numberCount > CommonConstant.ONE) {
                            throw new CheckException(31213108, "导入文件中准考证号重复");
                        }
                    });

                    // 库中准考证号是否重复
                    checkHandler.collect(studentValue, checkTarget -> {
                        Long numberCount = MapUtil.getLong(batchImportFileStatisticDTO.getAdmissionNoAccessCount(), checkTarget, CommonConstant.ROOT_ID);
                        if (numberCount >= CommonConstant.ONE) {
                            throw new CheckException(31213108, "数据库中准考证号重复");
                        }
                    });
                    break;
                case birthday:
                    checkHandler.collect(studentValue, checkTarget -> {
                        try {
                            DateTime dateTime = cn.hutool.core.date.DateUtil.parse(checkTarget);
                        } catch (Exception e) {
                            String exceptionMessage = StrUtil.format("出生日期<{}>存在格式不正确，请检查文件后重新导入", checkTarget);
                            throw new CheckException(31811124, exceptionMessage);
                        }
                    });
                    break;
                default:
                    break;
            }
        }

        return studentValue;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String batchImportManual(String projectId, List<StudentInfo> studentInfos, Boolean createFlag, List<String> submitSubjectIds) {
        log.info("[集体报名][手动录入] studentinfo add projectId:{}", projectId);
        // 判断是不是已经硬性截止了
        Project project = iProjectService.getById(projectId);
        Boolean validateSubmitEndResult = validateSingUpEnd(project);
        if (!validateSubmitEndResult) {
            BusinessLogicException.throwException(31081105, "报名已经截止了，不允许提交考生信息！");
        }

        if (CollUtil.size(submitSubjectIds) > project.getMaxSubject()) {
            BusinessLogicException.throwException(31081110, "选择的报考科目数量不能大于设置的最多可报考科目数量");
        }

        String studentId = UUIDUtils.newSortUUID();

        StudentProject entity = new StudentProject();
        entity.setId(studentId);
        entity.setProjectId(projectId);
        entity.setOfficeId(iBaseLoginService.getOfficeId());
        entity.setDeptId(iBaseLoginService.getDeptId());
        entity.setCreateBy(iBaseLoginService.getUserId());
        entity.setUpdateBy(iBaseLoginService.getUserId());
        entity.setCreateDate(LocalDateTime.now());
        entity.setUpdateDate(LocalDateTime.now());
        entity.setIsAudit(BmAuditStatusEnum.APPROVED.getAuditStatus());
        //加入考生的名字，手机，证件类型，证件号
        ansycStudentInfo(studentInfos, projectId, entity);
        iStudentProject.save(entity);

        if (CollectionUtils.isEmpty(studentInfos)) {
            BusinessLogicException.throwException(31081113, "当缺少考生采集信息");
        }

        List<StudentInfo> studentInfosTemp = new ArrayList<>();
        for (StudentInfo studentInfo : studentInfos) {
            if (StringUtils.isBlank(studentInfo.getValue())) {
                continue;
            }
            studentInfo.setProjectId(projectId);
            studentInfo.setStudentId(studentId);
            studentInfo.setId(UUIDUtils.newSortUUID());
            studentInfo.setCreateBy(iBaseLoginService.getUserId());
            studentInfo.setUpdateBy(iBaseLoginService.getUserId());
            studentInfo.setCreateDate(LocalDateTime.now());
            studentInfo.setUpdateDate(LocalDateTime.now());
            studentInfosTemp.add(studentInfo);
        }
        if (CollectionUtils.isEmpty(studentInfosTemp)) {
            BusinessLogicException.throwException(31081112, "当前操作没有有效的考生采集信息");
        }
        this.saveBatch(studentInfosTemp);

        // 后台录入，这里则需要对用户进行科目的绑定
        // 获取项目所有的科目
        List<ProjectSubject> subjectList = projectSubjectMapper.querySubjectList(projectId, null);
        // 考生科目列表
        List<StudentSubject> studentSubjectList = new ArrayList<StudentSubject>();
        if (CollectionUtils.isNotEmpty(subjectList)) {
            for (ProjectSubject projectSubject : subjectList) {
                // 如果选择的科目不为空
                if (CollUtil.isNotEmpty(submitSubjectIds)) {
                    // 系统的科目和选择的科目不一致就跳过
                    if (!CollUtil.contains(submitSubjectIds, projectSubject.getSubjectId())) {
                        continue;
                    }
                }
                // 集体报名默认报考所有科目，这个时候需要将报考的科目和配置的最大报考名额做校验
                Boolean validateStudentSubjectRegistNum = iStudentSubjectService.validateStudentSubjectRegistNum(projectSubject.getProjectId(), projectSubject.getSubjectId());
                if (!validateStudentSubjectRegistNum) {
                    InvalidRequestException.throwException(31081205, "科目配置的报名名额不足，请选择其他科目进行报考！");
                }

                StudentSubject studentSubject = new StudentSubject();
                studentSubject.setSubjectId(projectSubject.getSubjectId());
                studentSubject.setStudentId(studentId);
                studentSubject.setSubjectName(projectSubject.getSubjectName());
                studentSubject.setProjectId(projectId);
                studentSubject.setIsPay(projectSubject.getIsPay());
                studentSubject.setPay(BmPayStatusEnum.UNPAY.getPayStatus());
                studentSubject.setIsAudit(BmAuditStatusEnum.APPROVED.getAuditStatus());
                studentSubject.setCreateBy(iBaseLoginService.getUserId());
                studentSubject.setCreateDate(LocalDateTime.now());
                studentSubject.setUpdateBy(iBaseLoginService.getUserId());
                studentSubject.setUpdateDate(LocalDateTime.now());
                studentSubjectList.add(studentSubject);
            }
        }
        if (CollectionUtils.isEmpty(studentSubjectList)) {
            BusinessLogicException.throwException(31081111, "当前操作没有科目信息，请联系管理员");
        }
        // 集体报名默认报考所有科目，这个时候需要将报考的科目和项目设置的最大报考科目数做校验
        if (CollUtil.size(studentSubjectList) > project.getMaxSubject()) {
            InvalidRequestException.throwException(31081203, "选择的报考科目数量不能大于设置的最多可报考科目数量");
        }

        List<String> studentSubjectIds = studentSubjectList.stream()
                .map(StudentSubject::getSubjectId)
                .distinct()
                .collect(Collectors.toList());
        // 校验报名考生是否有资格
        iNonOpenService.checkStudentHasQualifications(projectId, studentInfos, studentSubjectIds);
        // 报考科目入库
        iStudentSubjectService.saveBatch(studentSubjectList);
        // 
        if(CollUtil.isNotEmpty(studentSubjectIds)) {
            // 修改报名资格为已报考
            List<NonOpenInfo> nonOpenInfos = iNonOpenService.getStudentQualificationByIdcard(project.getId(), studentInfos);
            if(CollUtil.isNotEmpty(nonOpenInfos)) {
                for (NonOpenInfo nonOpenInfo : nonOpenInfos) {
                    nonOpenInfo.setIsBm(Boolean.TRUE);
                }
                iNonOpenService.saveOrUpdateBatch(nonOpenInfos);
            }
        }
        // 创建一个新账号
        if (createFlag != null && createFlag) {
            createNewUaAccount(projectId, studentInfos, entity, project);
        }

        return studentId;
    }

    /**
     * 福建执法同步考生信息
     * @throws IOException 
     * @see IStudentInfoService#syncFjzfStudentInfo(FjzfSyncStudentDto)
     **/
    @Override
    public FjzfSyncStudentDto syncFjzfStudentInfo(FjzfSyncStudentDto fjzfSyncStudentDto) {
        // 首先根据考试科目获取最新的并且在报名开放期的报名项目
        Project project = iProjectService.getOpenProjectByName(fjzfSyncStudentDto.getOfficeId());
        if(null == project) {
            fjzfSyncStudentDto.setState(BmCustomerIntefaceState.FAIL.getCode());
            fjzfSyncStudentDto.setStateDesc("目前该区域通过模考人数较少，暂未开放预约报考功能。请保持关注预约平台信息！");
            return fjzfSyncStudentDto;
        }
        
        List<StudentInfo> studentInfos = new ArrayList<>();
        // 校验项目信息是不是存在
        String projectId = project.getId();
        // 获取姓名采集字段
        String nameCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.name.getCode(), projectId, DelFlagEnum.NORMAL.getCode());
        if(StrUtil.isEmptyIfStr(nameCollectId)) {
            fjzfSyncStudentDto.setState(BmCustomerIntefaceState.FAIL.getCode());
            fjzfSyncStudentDto.setStateDesc("报名项目没有姓名采集字段");
            return fjzfSyncStudentDto;
        } else {
            StudentInfo studentInfo = new StudentInfo();
            studentInfo.setProjectId(projectId);
            studentInfo.setProjectCollectInfoId(nameCollectId);
            studentInfo.setProjectCollectInfoName(ComponentNameEnum.name.getDesc());
            studentInfo.setValue(fjzfSyncStudentDto.getName());
            studentInfos.add(studentInfo);
        }
        
        // 获取性别采集字段
        String sexCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.sex.getCode(), projectId, DelFlagEnum.NORMAL.getCode());
        if(StrUtil.isEmptyIfStr(sexCollectId)) {
            fjzfSyncStudentDto.setState("0");
            fjzfSyncStudentDto.setStateDesc("报名项目没有性别采集字段");
            return fjzfSyncStudentDto;
        } else {
            StudentInfo studentInfo = new StudentInfo();
            studentInfo.setProjectId(projectId);
            studentInfo.setProjectCollectInfoId(sexCollectId);
            studentInfo.setProjectCollectInfoName(ComponentNameEnum.sex.getDesc());
            studentInfo.setValue(fjzfSyncStudentDto.getSex());
            studentInfos.add(studentInfo);
         }
        
        // 获取电话号码采集字段
        String phoneCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.phone.getCode(), projectId, DelFlagEnum.NORMAL.getCode());
        if(StrUtil.isEmptyIfStr(phoneCollectId)) {
            fjzfSyncStudentDto.setState(BmCustomerIntefaceState.FAIL.getCode());
            fjzfSyncStudentDto.setStateDesc("报名项目没有电话号码采集字段");
            return fjzfSyncStudentDto;
        } else {
            StudentInfo studentInfo = new StudentInfo();
            studentInfo.setProjectId(projectId);
            studentInfo.setProjectCollectInfoId(phoneCollectId);
            studentInfo.setProjectCollectInfoName(ComponentNameEnum.phone.getDesc());
            studentInfo.setValue(fjzfSyncStudentDto.getPhone());
            studentInfos.add(studentInfo);
         }
        
        // 获取证件类型采集字段
        String certificatetypeCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.certificatetype.getCode(), projectId, DelFlagEnum.NORMAL.getCode());
        if(StrUtil.isEmptyIfStr(certificatetypeCollectId)) {
            fjzfSyncStudentDto.setState(BmCustomerIntefaceState.FAIL.getCode());
            fjzfSyncStudentDto.setStateDesc("报名项目没有证件类型采集字段");
            return fjzfSyncStudentDto;
        } else {
            StudentInfo studentInfo = new StudentInfo();
            studentInfo.setProjectId(projectId);
            studentInfo.setProjectCollectInfoId(certificatetypeCollectId);
            studentInfo.setProjectCollectInfoName(ComponentNameEnum.certificatetype.getDesc());
            studentInfo.setValue(fjzfSyncStudentDto.getCardType());
            studentInfos.add(studentInfo);
        }
        
        // 获取姓名采集字段
        String idcardCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.idcard.getCode(), projectId, DelFlagEnum.NORMAL.getCode());
        if(StrUtil.isEmptyIfStr(idcardCollectId)) {
            fjzfSyncStudentDto.setState(BmCustomerIntefaceState.FAIL.getCode());
            fjzfSyncStudentDto.setStateDesc("报名项目没有证件号码采集字段");
            return fjzfSyncStudentDto;
        } else {
            StudentInfo studentInfo = new StudentInfo();
            studentInfo.setProjectId(projectId);
            studentInfo.setProjectCollectInfoId(idcardCollectId);
            studentInfo.setProjectCollectInfoName(ComponentNameEnum.idcard.getDesc());
            studentInfo.setValue(fjzfSyncStudentDto.getCardNumber());
            studentInfos.add(studentInfo);
        }
        
        // 获取证件照采集字段
        String idcardphotoCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.certificatephoto.getCode(), projectId, DelFlagEnum.NORMAL.getCode());
        if(StrUtil.isEmptyIfStr(idcardphotoCollectId)) {
            fjzfSyncStudentDto.setState(BmCustomerIntefaceState.FAIL.getCode());
            fjzfSyncStudentDto.setStateDesc("报名项目没有证件照片采集字段");
            return fjzfSyncStudentDto;
        } else {
            StudentInfo studentInfo = new StudentInfo();
            studentInfo.setProjectId(projectId);
            studentInfo.setProjectCollectInfoId(idcardphotoCollectId);
            studentInfo.setProjectCollectInfoName(ComponentNameEnum.idcardphoto.getDesc());
            //studentInfo.setValue(transferPhoto(fjzfSyncStudentDto.getPhoto(), fjzfSyncStudentDto.getOfficeId(), projectId, fjzfSyncStudentDto.getCardNumber()));
            studentInfo.setValue(fjzfSyncStudentDto.getPhoto());
            studentInfos.add(studentInfo);
        }
        
        // 获取地区code采集字段
        String areaCodeCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.area.getCode(), projectId, DelFlagEnum.NORMAL.getCode());
        if(StrUtil.isBlank(areaCodeCollectId)) {
            fjzfSyncStudentDto.setState(BmCustomerIntefaceState.FAIL.getCode());
            fjzfSyncStudentDto.setStateDesc("报名项目没有区域编码采集字段");
            return fjzfSyncStudentDto;
        } else {
            ProjectCollectInfoOption areaCodeCollectInfoOption = getProjectCollectInfoOptionByValue(fjzfSyncStudentDto.getAreaCode(), areaCodeCollectId, projectId);
            if (areaCodeCollectInfoOption == null) {
                fjzfSyncStudentDto.setState(BmCustomerIntefaceState.FAIL.getCode());
                fjzfSyncStudentDto.setStateDesc("报名项目区域编码采集字段未匹配到对应的地区");
                return fjzfSyncStudentDto;
            }
            
            // title与对应的采集信息数据
            String studentAreaCodeValue = buildOptionTreeRealValueByValue(fjzfSyncStudentDto.getAreaCode(), areaCodeCollectId, projectId);
            
            StudentInfo studentInfo = new StudentInfo();
            studentInfo.setProjectId(projectId);
            studentInfo.setProjectCollectInfoId(areaCodeCollectId);
            studentInfo.setProjectCollectInfoName(ComponentNameEnum.area.getDesc());
            studentInfo.setValue(studentAreaCodeValue);
            studentInfos.add(studentInfo);
        }
        
        // 资格录入的时候首先根据科目名称查询科目列表
        String subjectIds = getProjectSubjectBySubjectName(projectId, fjzfSyncStudentDto.getSubjectName());
        if(StrUtil.isEmptyIfStr(subjectIds)) {
            fjzfSyncStudentDto.setState(BmCustomerIntefaceState.FAIL.getCode());
            fjzfSyncStudentDto.setStateDesc("报名项目没有可报考的科目信息");
            return fjzfSyncStudentDto;
        }
        
        // 考生同步分布式锁
        StringBuilder studentLockKey = new StringBuilder();
        studentLockKey.append(RedisKeyConstant.STUDENT_SYNC);
        studentLockKey.append(projectId);
        studentLockKey.append(StrPool.COLON);
        studentLockKey.append(fjzfSyncStudentDto.getCardNumber());

        RLock lock = redissonClient.getLock(studentLockKey.toString());
        try {
            boolean b = lock.tryLock(RedisKeyConstant.LOCK_TIME, TimeUnit.SECONDS);
            if (b) {
                log.info("# syncFjzfStudentInfo {}, get lock", studentLockKey.toString());
                String userId = syncSaveStudentInfo(project, studentInfos, idcardCollectId, fjzfSyncStudentDto.getCardNumber(), subjectIds, fjzfSyncStudentDto, phoneCollectId, certificatetypeCollectId, areaCodeCollectId);
                fjzfSyncStudentDto.setBmStudentId(userId);
                fjzfSyncStudentDto.setState(BmCustomerIntefaceState.SUCCESS.getCode());
                fjzfSyncStudentDto.setStateDesc("同步考生成功");
                return fjzfSyncStudentDto;
            }
        } catch (InterruptedException e) {
            log.error("Interrupted!", e);
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
        fjzfSyncStudentDto.setState(BmCustomerIntefaceState.SUCCESS.getCode());
        fjzfSyncStudentDto.setStateDesc("同步考生成功");
        return fjzfSyncStudentDto;
    }

    /**
     * 构造报名采集项树形结构真实value
     *
     * @param studentValue
     * @param projectCollectInfoId
     * @param projectId
     * @return
     */
    @Override
    public String buildOptionTreeRealValueByValue(String studentValue, String projectCollectInfoId, String projectId) {
        boolean fullStatus = true;
        String tempValue = studentValue;
        do {
            ProjectCollectInfoOption projectCollectInfoOptionCurrent = getProjectCollectInfoOptionByValue(tempValue, projectCollectInfoId, projectId);
            if (projectCollectInfoOptionCurrent != null) {
                String parentOptionValue = projectCollectInfoOptionCurrent.getParentOptionValue();
                if (StrUtil.isBlank(parentOptionValue)) {
                    fullStatus = false;
                } else {
                    studentValue = parentOptionValue + StrPool.COMMA + studentValue;
                    tempValue = parentOptionValue;
                }
            } else {
                fullStatus = false;
            }
        } while (fullStatus);
        return studentValue;
    }

    /**
     * 获取选项通过值
     *
     * @param optionValue
     * @param projectCollectInfoId
     * @param projectId
     * @return
     */
    private ProjectCollectInfoOption getProjectCollectInfoOptionByValue(String optionValue, String projectCollectInfoId, String projectId) {
        ProjectCollectInfoOption projectCollectInfoOptionCurrent = iProjectCollectInfoOptionService.lambdaQuery()
                .eq(BaseEntity::getDelFlag, Boolean.FALSE)
                .eq(ProjectCollectInfoOption::getProjectId, projectId)
                .eq(ProjectCollectInfoOption::getProjectCollectInfoId, projectCollectInfoId)
                .eq(ProjectCollectInfoOption::getOptionValue, optionValue)
                .orderByDesc(BaseEntity::getCreateDate)
                .last(LIMIT_1)
                .one();
        return projectCollectInfoOptionCurrent;
    }

    @SneakyThrows
    public String buildOptionTreeRealValueByLabel(String studentValueLabel, String projectCollectInfoId, String projectId) {
        List<ProjectCollectInfoVo> projectCollectInfoVos = iProjectCollectInfoService.queryBaseCj(projectId);

        String studentAreaCodeValue = buildOptionTreeRealValueByLabel(studentValueLabel, projectCollectInfoId, projectCollectInfoVos);
        return studentAreaCodeValue;
    }

    @Override
    public String buildOptionTreeRealValueByLabel(String studentValueLabel, String projectCollectInfoId, List<ProjectCollectInfoVo> projectCollectInfoVos) {
        Map<String, ProjectCollectInfoVo> projectCollectInfoIdMappingData = projectCollectInfoVos.stream()
                .collect(Collectors.toMap(ProjectCollectInfo::getId, Function.identity(), (k1, k2) -> k1));
        ProjectCollectInfoVo projectCollectInfoVo = projectCollectInfoIdMappingData.get(projectCollectInfoId);

        String studentValueLabelName = studentValueLabel;
        if (CollectionUtils.isNotEmpty(projectCollectInfoVo.getOptionList())) {
            ProjectCollectInfoOption projectCollectInfoOption = null;
            for (int k = 0; k < projectCollectInfoVo.getOptionList().size(); k++) {
                ProjectCollectInfoOption projectCollectInfoOptionTemp = CollUtil.get(projectCollectInfoVo.getOptionList(), k);
                if (StrUtil.equals(studentValueLabelName,projectCollectInfoOptionTemp.getOptionLabel())) {
                    projectCollectInfoOption = projectCollectInfoOptionTemp;
                }
            }
            if (null != projectCollectInfoOption) {
                // 如果是下拉级联组件，需要设置层级结构
                if (StrUtil.equals(projectCollectInfoVo.getComponentType(), ComponentTypeEnum.cascader.getType())) {
                    // 如果下拉复选的层级为空，则生成层级结构数据落库
                    if (StrUtil.isBlank(projectCollectInfoOption.getOptionLevel())) {
                        studentValueLabelName = getOptionsLevelValue(studentValueLabelName, projectCollectInfoOption, projectCollectInfoVo.getOptionList());
                    }
                }
            }
        }
        return studentValueLabelName;
    }
    
    
    /**
     * 将不安全的链接转换成安全链接
     * @param photo
     * @param officeId
     * @return
     * @throws IOException 
     */
    private String transferPhoto(String photo, String officeId, String projectId, String idCard)  {
        if(StrUtil.isEmptyIfStr(photo)) {
            return photo;
        }
        if(photo.startsWith("https://")) {
            return photo;
        }
        if(photo.startsWith("http://")) {
            FileInputStream fis = null;
            try {
                ApiResponse<Bucket> tempCredentialResponse = tpsClient.getTencentCosTempCredential(officeId);
                ProgressManager.updateProgressCurrent(40L, "文件开始上传");
                if (tempCredentialResponse.getCode() != 1) {
                    return photo;
                }
                String domain = tempCredentialResponse.getData().getDomain();
                File temFile = FileUtil.createTempFile(idCard, ".jpg", true);
                temFile.deleteOnExit();
                // 先将图片下载到本地
                HttpUtil.downloadFileFromUrl(photo, temFile);
                // 转换成字节流
                byte[] bytesArray = new byte[(int) temFile.length()];
                fis  = new FileInputStream(temFile);
                while (true){
                    int read =  fis.read(bytesArray);
                    if(read == -1){
                        break;
                    }
                }

                // 设置图片的名称
                String newFileName = idCard + ".jpg";
                //使用腾讯云COS上传
                String path = TencentCloudCosUtil.getPhotoRootPath(projectId) + newFileName;
                ApiResponse<String> uploadResponse = tpsClient.uploadTencentCosCompressedPhoto(officeId, path, bytesArray);
                if (uploadResponse.getCode() != 1) {
                    return photo;
                }
                String newPhotoUrl = domain + "/" + uploadResponse.getData();
                log.info("# newPhotoUrl{}", newPhotoUrl);
                return newPhotoUrl;
            } catch (Exception e) {
                log.error("# transferPhoto:{} error", photo, e);
            } finally {
                IoUtil.close(fis);
            }
        }
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    public String syncSaveStudentInfo(Project project, List<StudentInfo> studentInfos, String idcardCollectId, String cardNumber, String subjectIds, FjzfSyncStudentDto fjzfSyncStudentDto, String phoneCollectId, String certificateTypeCollectId, String areaCodeCollectId) {
        String studentNewPhone = fjzfSyncStudentDto.getPhone();
        String studentNewCardType = fjzfSyncStudentDto.getCardType();
        String oldIdCard = cardNumber;
        boolean phoneUpdateStatus = false;
        boolean idCardUpdateStatus = false;
        boolean idCardTypeUpdateStatus = false;
        // 项目ID
        String projectId = project.getId();
        String userId = fjzfSyncStudentDto.getBmStudentId();
        String studentId = null;
        String deptId = project.getDeptId();

        
        // 首先查询是否存在考生
        QueryWrapper<StudentProject> studentProjeQueryWrapper = new QueryWrapper<>();
        studentProjeQueryWrapper.lambda()
                .eq(StudentProject::getProjectId, projectId)
                .eq(StudentProject::getDelFlag, Boolean.FALSE)
                .eq(StrUtil.isNotBlank(userId) , StudentProject::getRegId, userId)
                .eq(StrUtil.isBlank(userId) , StudentProject::getCardNumber, cardNumber)
                .last("limit 1");

        StudentProject studentProject  = iStudentProjectService.getOne(studentProjeQueryWrapper);
        if (null != studentProject) {
            studentId = studentProject.getId();
            oldIdCard = studentProject.getCardNumber();
            // 手机号不一样就是修改了手机号码
            phoneUpdateStatus = !StrUtil.equals(studentProject.getPhone(), studentNewPhone);
            // 身份证号不一样就是修改了身份证号码
            idCardUpdateStatus = !StrUtil.equals(studentProject.getCardNumber(), cardNumber);
            // 证件类型不一样就是修改了身份证类型
            idCardTypeUpdateStatus = !StrUtil.equals(studentProject.getCardType(), studentNewCardType);
            
            studentProject.setUpdateDate(LocalDateTime.now());
            studentProject.setUpdateBy(iBaseLoginService.getUserId());
            studentProject.setIsAudit(Project.getStudentAuditStatus(project.getIsVerify()));
            //加入考生的名字，手机，证件类型，证件号
            ansycStudentInfo(studentInfos, projectId, studentProject);
            studentProject.setDeptId(deptId);
            iStudentProject.updateById(studentProject);
            
        } else {
            // 没报名
            studentProject = new  StudentProject();
            studentId = UUIDUtils.newSortUUID();
            studentProject.setId(studentId);
            studentProject.setRegId(userId);
            studentProject.setProjectId(projectId);
            studentProject.setOfficeId(iBaseLoginService.getOfficeId());
            studentProject.setCreateBy(iBaseLoginService.getUserId());
            studentProject.setUpdateBy(iBaseLoginService.getUserId());
            studentProject.setCreateDate(LocalDateTime.now());
            studentProject.setUpdateDate(LocalDateTime.now());
            studentProject.setIsAudit(Project.getStudentAuditStatus(project.getIsVerify()));
            //加入考生的名字，手机，证件类型，证件号
            ansycStudentInfo(studentInfos, projectId, studentProject);
            studentProject.setDeptId(deptId);
            iStudentProject.save(studentProject);
        }
        

        // 如果考生信息不存在，则新增考生信息
        if (CollectionUtils.isNotEmpty(studentInfos)) {
            // 查询当前考生是否有考生信息
            List<StudentInfo> databaseStudentInfo = this.listByStudentId(projectId, studentId);
            // 如果考生信息是新增
            if (CollUtil.isEmpty(databaseStudentInfo)) {
                List<StudentInfo> studentInfosTemp = new ArrayList<>();
                for (StudentInfo studentInfo : studentInfos) {
                    if (StringUtils.isEmpty(studentInfo.getValue())) {
                        continue;
                    }
                    studentInfo.setId(UUIDUtils.newSortUUID());
                    studentInfo.setProjectId(projectId);
                    studentInfo.setStudentId(studentId);
                    studentInfo.setCreateBy(iBaseLoginService.getUserId());
                    studentInfo.setUpdateBy(iBaseLoginService.getUserId());
                    studentInfo.setCreateDate(LocalDateTime.now());
                    studentInfo.setUpdateDate(LocalDateTime.now());
                    studentInfosTemp.add(studentInfo);
                }
                if (CollectionUtils.isNotEmpty(studentInfosTemp)) {
                    this.saveBatch(studentInfosTemp);
                }
            } else {
                // 手机号码更新
                if (phoneUpdateStatus) {
                    this.lambdaUpdate()
                            .eq(StudentInfo::getProjectId, projectId)
                            .eq(StudentInfo::getStudentId, studentId)
                            .eq(StudentInfo::getProjectCollectInfoId, phoneCollectId)
                            .eq(BaseEntity::getDelFlag, Boolean.FALSE)
                            .set(StudentInfo::getValue, fjzfSyncStudentDto.getPhone())
                            .set(BaseEntity::getUpdateBy, iBaseLoginService.getUserId())
                            .set(BaseEntity::getUpdateDate, LocalDateTime.now())
                            .update();
                }
                // 证件号码更新
                if (idCardUpdateStatus) {
                    this.lambdaUpdate()
                            .eq(StudentInfo::getProjectId, projectId)
                            .eq(StudentInfo::getStudentId, studentId)
                            .eq(StudentInfo::getProjectCollectInfoId, idcardCollectId)
                            .eq(BaseEntity::getDelFlag, Boolean.FALSE)
                            .set(StudentInfo::getValue, fjzfSyncStudentDto.getCardNumber())
                            .set(BaseEntity::getUpdateBy, iBaseLoginService.getUserId())
                            .set(BaseEntity::getUpdateDate, LocalDateTime.now())
                            .update();
                }
                // 证件类型更新
                if (idCardTypeUpdateStatus) {
                    this.lambdaUpdate()
                            .eq(StudentInfo::getProjectId, projectId)
                            .eq(StudentInfo::getStudentId, studentId)
                            .eq(StudentInfo::getProjectCollectInfoId, certificateTypeCollectId)
                            .eq(BaseEntity::getDelFlag, Boolean.FALSE)
                            .set(StudentInfo::getValue, fjzfSyncStudentDto.getCardType())
                            .set(BaseEntity::getUpdateBy, iBaseLoginService.getUserId())
                            .set(BaseEntity::getUpdateDate, LocalDateTime.now())
                            .update();
                }
                // 地区code码更新
                if (StrUtil.isNotBlank(areaCodeCollectId)) {
                    String newAreaCode = studentInfos.stream()
                            .filter(data -> StrUtil.isNotBlank(data.getValue()))
                            .filter(studentInfo -> StrUtil.equals(studentInfo.getProjectCollectInfoId(), areaCodeCollectId))
                            .findFirst()
                            .map(StudentInfo::getValue)
                            .orElse(fjzfSyncStudentDto.getAreaCode());

                    StudentInfo databaseArea = this.getStudentInfoByCollectInfoId(projectId, studentId, areaCodeCollectId);
                    // 如果存在就更新，不存在就新增
                    if (databaseArea != null) {
                        this.lambdaUpdate()
                                .eq(StudentInfo::getProjectId, projectId)
                                .eq(StudentInfo::getStudentId, studentId)
                                .eq(StudentInfo::getProjectCollectInfoId, areaCodeCollectId)
                                .eq(BaseEntity::getDelFlag, Boolean.FALSE)
                                .set(StudentInfo::getValue, newAreaCode)
                                .set(BaseEntity::getUpdateBy, iBaseLoginService.getUserId())
                                .set(BaseEntity::getUpdateDate, LocalDateTime.now())
                                .update();
                    } else {
                        StudentInfo studentInfoAreSave = new StudentInfo();
                        studentInfoAreSave.setProjectId(projectId);
                        studentInfoAreSave.setProjectCollectInfoId(areaCodeCollectId);
                        studentInfoAreSave.setProjectCollectInfoName(ComponentNameEnum.area.getDesc());
                        studentInfoAreSave.setValue(newAreaCode);
                        studentInfoAreSave.setId(UUIDUtils.newSortUUID());
                        studentInfoAreSave.setProjectId(projectId);
                        studentInfoAreSave.setStudentId(studentId);
                        studentInfoAreSave.setCreateBy(iBaseLoginService.getUserId());
                        studentInfoAreSave.setUpdateBy(iBaseLoginService.getUserId());
                        studentInfoAreSave.setCreateDate(LocalDateTime.now());
                        studentInfoAreSave.setUpdateDate(LocalDateTime.now());
                        this.save(studentInfoAreSave);
                    }
                }
            }
        }
        // 首先查询报名资格是不是存在
        QueryWrapper<NonOpenInfo> nonOpenInfoQueryWrapper = new QueryWrapper<>();
        nonOpenInfoQueryWrapper.lambda()
                .eq(BaseEntity::getDelFlag, Boolean.FALSE)
                .eq(NonOpenInfo::getProjectId, studentProject.getProjectId())
                .eq(NonOpenInfo::getCardNumber, oldIdCard)
                .last("LIMIT 1");
        
        NonOpenInfo nonOpenInfo = iNonOpenService.getOne(nonOpenInfoQueryWrapper);
        if(null == nonOpenInfo) {
            // 添加报名资格
            NonOpenInfo nonOpenInfoSave = new NonOpenInfo();;
            // 如果为新增，则用当前报名信息中的机构信息
            nonOpenInfoSave.setId(UUIDUtils.newSortUUID());
            nonOpenInfoSave.setDeptId(project.getDeptId());
            nonOpenInfoSave.setOfficeId(project.getOfficeId());
            nonOpenInfoSave.setStudentName(studentProject.getName());
            nonOpenInfoSave.setCardType(studentProject.getCardType());
            nonOpenInfoSave.setCardNumber(studentProject.getCardNumber());
            nonOpenInfoSave.setProjectId(project.getId());
            nonOpenInfoSave.setSubjectIds(subjectIds);
            nonOpenInfoSave.setCreateBy(iBaseLoginService.getUserId());
            nonOpenInfoSave.setCreateDate(LocalDateTime.now());
            nonOpenInfoSave.setUpdateBy(iBaseLoginService.getUserId());
            nonOpenInfoSave.setUpdateDate(LocalDateTime.now());
            nonOpenInfoSave.setDelFlag(Boolean.FALSE);
            iNonOpenService.save(nonOpenInfoSave);
        } else {
            // 获取老报名资格的科目信息
            String oldsubjectIds = nonOpenInfo.getSubjectIds();
            List<String> addList = new ArrayList<>();
            List<String> delList = new ArrayList<>();
            nonOpenInfo.setSubjectIds(oldsubjectIds);
            if(StrUtil.isNotEmpty(subjectIds)) {
                List<String> oldSubjectIdList = StrUtil.split(oldsubjectIds, StrPool.COMMA);
                List<String> newSubkjectIdList = StrUtil.split(subjectIds, StrPool.COMMA);
                CompareUtil.filterList(oldSubjectIdList, newSubkjectIdList, addList, delList);
            }
            if(CollUtil.isNotEmpty(addList)){
                nonOpenInfo.setSubjectIds(oldsubjectIds +  StrPool.COMMA + String.join(StrPool.COMMA, addList));
            }
            nonOpenInfo.setCardType(studentProject.getCardType());
            nonOpenInfo.setCardNumber(studentProject.getCardNumber());
            nonOpenInfo.setStudentName(studentProject.getName());
            nonOpenInfo.setUpdateBy(iBaseLoginService.getUserId());
            nonOpenInfo.setUpdateDate(LocalDateTime.now());
            nonOpenInfo.setDelFlag(Boolean.FALSE);   
            iNonOpenService.saveOrUpdate(nonOpenInfo);
        }

        if (StrUtil.isBlank(userId)) {
            // 创建一个新账号
            userId = createNewUaAccount(projectId, studentInfos, studentProject, project);
        } else {
            UserPhoneEditVO userPhoneEditVO = new UserPhoneEditVO();
            userPhoneEditVO.setUserId(userId)
                    .setPhone(fjzfSyncStudentDto.getPhone());
            userId = RemoteUtil.getOrThrows(() -> permissionLoginClient.updatePhoneCandidate(userPhoneEditVO));
        } 
        
        return userId;
    }
    
    /**
     * //TODO 添加override说明
     * @see com.hyt.it.ogt.kq.service.bm.service.IStudentInfoService#getValueByStudentIdAndCollectInfoId(java.lang.String, java.lang.String, java.lang.String)
     **/
    @Override
    public String getValueByStudentIdAndCollectInfoId(String projectId, String studentId, String collectInfoId) {
        QueryWrapper<StudentInfo> studentCollValueQueryWrapper = new QueryWrapper<>();
        studentCollValueQueryWrapper.lambda()
                .eq(StudentInfo::getProjectId, projectId)
                .eq(StudentInfo::getStudentId, studentId)
                .eq(StudentInfo::getProjectCollectInfoId, collectInfoId)
                .last("limit 1");
        StudentInfo studentInfo = getOne(studentCollValueQueryWrapper);
        if(null != studentInfo) {
            if(StrUtil.isNotBlank(studentInfo.getValue())) {
                return studentInfo.getValue();
            }
        }
        return null;
    }

    @Override
    public StudentInfo getStudentInfoByCollectInfoId(String projectId, String studentId, String projectCollectInfoId) {
        return this.lambdaQuery()
                .eq(BaseEntity::getDelFlag, Boolean.FALSE)
                .eq(StudentInfo::getProjectId, projectId)
                .eq(StudentInfo::getStudentId, studentId)
                .eq(StudentInfo::getProjectCollectInfoId, projectCollectInfoId)
                .orderByDesc(BaseEntity::getCreateDate)
                .last(LIMIT_1)
                .one();
    }


    /**
     * 通过项目Id和科目名称模糊匹配可以报考的科目
     * @param projectId 项目名称
     * @param subjectName 科目名称
     * 
     **/
    public String getProjectSubjectBySubjectName(String projectId, String subjectName) {
        QueryWrapper<ProjectSubject> projectSubjectQueryWrapper = new QueryWrapper<>();
        projectSubjectQueryWrapper.lambda()
                .eq(ProjectSubject::getProjectId, projectId)
                .eq(ProjectSubject::getDelFlag, Boolean.FALSE);
        
        if (StrUtil.isNotEmpty(subjectName)) {
            projectSubjectQueryWrapper.and((wra) -> {
                wra.lambda().like(ProjectSubject::getSubjectName, subjectName);
            });
        }
        
        StringBuilder stringBuilder = new StringBuilder();
        List<ProjectSubject> projectSubjects = iProjectSubjectService.list(projectSubjectQueryWrapper);
        if(CollUtil.isNotEmpty(projectSubjects)) {
            for (ProjectSubject projectSubject : projectSubjects) {
                stringBuilder.append(projectSubject.getSubjectId());
                stringBuilder.append(",");
            }
            return stringBuilder.deleteCharAt(stringBuilder.length()-1).toString();
        }
        return null;
    }

}
